使用反射获取对象属性并显示到Treeview

Using Reflection to obtain object properties and display onto Treeview

我一直在寻找最好地完成这项任务的方法并最终确定了这一点。

https://rbrundritt.wordpress.com/2012/01/30/view-object-properties-in-wpf-treeview/

它似乎确实给了我我所希望的,但是当我尝试获取线程的对象属性时,我最终得到了一个 Whosebug 异常。因此,似乎 objectNode class 以递归方式实例化自身太多次,然后发生导致堆栈溢出的事情?我不确定如何着手解决这个问题并使其即使对于具有许多属性(如线程)的 class 也能正常工作,我们将不胜感激。

对象节点class如下图

using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Reflection;

namespace Server.Host
{
    public class ObjectNode 
    {
        #region Private Properties
        private string _name;
        private object _value;
        private Type _type;
        #endregion

        #region Constructor
        public ObjectNode(object value) 
        {
            ParseObjectTree("root", value, value.GetType());
        }

        public ObjectNode(string name, object value)
        {
            ParseObjectTree(name, value, value.GetType());
        }

        public ObjectNode(object value, Type t)
        {
            ParseObjectTree("root", value, t);
        }

        public ObjectNode(string name, object value, Type t)
        {
            ParseObjectTree(name, value, t);
        }
        #endregion

        #region Public Properties
        public string Name
        {
            get { return _name; }
        }

        public object Value
        {
            get { return _value; }
        }

        public Type Type
        {
            get { return _type; }
        }

        public ObservableCollection<ObjectNode> Children { get; set; }
        #endregion

        #region Private Methods
        private void ParseObjectTree(string name, object value, Type type)
        {
            Children = new ObservableCollection<ObjectNode>();

            _type = type;
            _name = name;

            if (value != null)
            {
                if (value is string && type != typeof(object))
                {
                    if (value != null)
                    {
                        _value = "\"" + value + "\"";
                    }
                }
                else if (value is double || value is bool || value is int || value is float || value is long || value is decimal)
                {
                    _value = value;
                }
                else
                {
                    _value = "{" + value.ToString() + "}";
                }
            }

            PropertyInfo[] props = type.GetProperties();

            if (props.Length == 0 && type.IsClass && value is IEnumerable && !(value is string))
            {
                IEnumerable arr = value as IEnumerable;

                if (arr != null)
                {
                    int i = 0;
                    foreach (object element in arr)
                    {
                        Children.Add(new ObjectNode("[" + i + "]", element, element.GetType()));
                        i++;
                    }
                }
            }

            foreach (PropertyInfo p in props)
            {
                if (p.PropertyType.IsPublic)
                {
                    if (p.PropertyType.IsClass || p.PropertyType.IsArray || p.PropertyType.IsInterface)
                    {
                        if (p.PropertyType.IsArray)
                        {
                            try
                            {
                                object v = p.GetValue(value, null);
                                IEnumerable arr = v as IEnumerable;

                                ObjectNode arrayNode = new ObjectNode(p.Name, arr.ToString(), typeof(object));

                                if (arr != null)
                                {
                                    int i = 0, k = 0;
                                    ObjectNode arrayNode2;

                                    foreach (object element in arr)
                                    {
                                        //Handle 2D arrays
                                        if (element is IEnumerable && !(element is string))
                                        {
                                            arrayNode2 = new ObjectNode("[" + i + "]", element.ToString(), typeof(object));

                                            IEnumerable arr2 = element as IEnumerable;
                                            k = 0;

                                            foreach (object e in arr2)
                                            {
                                                arrayNode2.Children.Add(new ObjectNode("[" + k + "]", e, e.GetType()));
                                                k++;
                                            }

                                            arrayNode.Children.Add(arrayNode2);
                                        }
                                        else
                                        {
                                            arrayNode.Children.Add(new ObjectNode("[" + i + "]", element, element.GetType()));
                                        }
                                        i++;
                                    }

                                }

                                Children.Add(arrayNode);
                            }
                            catch { }
                        }
                        else
                        {
                            object v = p.GetValue(value, null);

                            if (v != null)
                            {
                                Children.Add(new ObjectNode(p.Name, v, p.PropertyType));
                            }
                        }
                    }
                    else if (p.PropertyType.IsValueType && !(value is string))
                    {
                        try
                        {
                            object v = p.GetValue(value, null);

                            if (v != null)
                            {
                                Children.Add(new ObjectNode(p.Name, v, p.PropertyType));
                            }
                        }
                        catch { }
                    }
                }
            }
        }

        #endregion
    }
}

因此,可以将 TreeView 添加到 WPF 中,就像

<TreeView Name="ResultTreeView" BorderThickness="0">
                <TreeView.Resources>
                    <HierarchicalDataTemplate DataType="{x:Type local:ObjectNode}" 
                                              ItemsSource="{Binding Path=Children}">
                        <TreeViewItem>
                            <TreeViewItem.Header>
                                <StackPanel Orientation="Horizontal" Margin="-10,0,0,0">
                                    <TextBlock Text="{Binding Path=Name}"/>
                                    <TextBlock Text=" : "/>
                                    <TextBlock Text="{Binding Path=Value}"/>
                                </StackPanel>
                            </TreeViewItem.Header>
                        </TreeViewItem>
                    </HierarchicalDataTemplate>
                </TreeView.Resources>
            </TreeView>

然后在我的代码中,我简单地写

private Foo foo = new Foo();
ObservableCollection<ObjectNode> nodes = new ObservableCollection<ObjectNode>();
nodes.Add(new ObjectNode("result", foo));
ResultTreeView.ItemsSource = nodes;

其中 Foo 可以是任何 class。对于大多数事情,它工作正常。但是如果我在 class 中有一个线程,它将抛出异常。例如只是一个简单的

public class Foo
{
    public Foo()
    {
        Bar = new Thread(Baz);
    }

    public Thread Bar { get; set; }

    private static void Baz()
    {
    }
}

抛出的错误是 "An unhandled exception of type 'System.WhosebugException' occurred in mscorlib.dll"

再一次,非常欢迎任何建议。

从 ObjectNode class 的构造函数调用的 ParseObjectTree 方法似乎递归且无休止地实例化此 class 的其他实例。这就是 WhosebugException 的原因。您需要一种算法来限制递归,可能是通过计算世代数。