【问题标题】:Function to create a tree of properties?创建属性树的函数?
【发布时间】:2011-04-21 12:27:16
【问题描述】:

我正在尝试为对象创建一个属性列表。我可以很好地为基本对象创建一个列表,但是如果我遇到类型对象 A 包含对象 B 类型的属性的情况,该属性包含对象 A 类型的属性......好吧..然后我得到无限递归。 我所做的是向我的所有对象添加一个名为“RecursivePropertyList”的静态属性,它是每个具有递归的属性的List<string>

所以,例如: 我有一个Person 类,其属性名为Vendor,类型为VendorVendor 类有一个名为 People 的属性,其类型为 List<Person>

Person 类中,我将RecursivePropertyList 的值设置为myList.Add("Vendor.People")。 在Vendor类中,我将RecursivePropertyList的值设置为myList.Add("People.Vendor")

然后在创建属性列表的函数中,我检查当前的 objectname.propertyName 是否在 RecursivePropertyList 中,如果是,我不会将其添加到我的属性列表中,也不会向下钻取进入它以获取其属性。

这在上述情况下效果很好。

但是,当我遇到以下情况时,它开始失败: 具有List<ApplicationFunction_Application> 类型属性的Application 类。 具有List<ApplicationFunction_Application> 类型属性的ApplicationFunction 类。 一个ApplicationFunction_Application 类,它有两个属性,一个是Application 类型,另一个是ApplicationFunction 类型。 ApplicationFunction_Application 类的目的是定义ApplicationApplicationFunction 之间的多对多关系。

ApplicationRecursivePropertyList 中我放了:

myList.Add("ApplicationFunctions.Application");

ApplicationFunctionRecursivePropertyList 中我放了:

myList.Add("Applications.ApplicationFunction");

ApplicationFunction_ApplicationRecursivePropertyList 中我放了:

myList.Add("ApplicationFunction.Applications");

myList.Add("Application.ApplicationFunctions");

但是,我的脚本一直在循环,永远不会停止。

这里是函数使用的代码:

首先,开始整个事情的被调用函数:

public static EquatableList<PropertyState> FillPropertyStateList(System.Type myObjectType, ref EquatableList<PropertyState> myPropertyStateList)
        {
            List<string> myRecursivePropertyList = FillDefaultRecursivePropertyList(myObjectType);
            return FillPropertyStateList(myObjectType, ref myPropertyStateList, string.Empty, string.Empty, myRecursivePropertyList);
        }

然后是完成工作并递归调用自身以生成所有子对象的属性列表的函数。

public static EquatableList<PropertyState> FillPropertyStateList(System.Type myObjectType, ref EquatableList<PropertyState> myPropertyStateList, string myParentPrefix, string myObjectName, List<string> myRecursivePropertyList)
        {
            if (myPropertyStateList == null)
            {
                myPropertyStateList = new EquatableList<PropertyState>();
            }
            if (string.IsNullOrEmpty(myParentPrefix))
            {
                myParentPrefix = string.Empty;
            }
            else if (!myParentPrefix.EndsWith("."))
            {
                myParentPrefix = myParentPrefix + ".";
            }
            if (string.IsNullOrEmpty(myObjectName))
            {
                myObjectName = string.Empty;
            }
            else
            {
                myObjectName = myObjectName + ".";
            }

            foreach (System.Reflection.PropertyInfo info in myObjectType.GetProperties())
            {
                if (info.PropertyType.BaseType == typeof(BOBase))
                {
                    if (!myRecursivePropertyList.Exists(delegate(string x) { return x.Equals(myObjectName + info.Name); }))
                    {
                        myPropertyStateList.Add(new PropertyState(myParentPrefix + myObjectName + info.Name, true, PropertyType.BOBase));
                        List<string> myChildRecursivePropertyList = FillDefaultRecursivePropertyList(info.PropertyType);
                        myChildRecursivePropertyList.AddRange(myRecursivePropertyList.FindAll(delegate(string x) { return Regex.IsMatch(x, info.Name + ".*"); }));
                        FillPropertyStateList(info.PropertyType, ref myPropertyStateList, myParentPrefix + myObjectName, info.Name, myChildRecursivePropertyList);
                    }
                }
                else if (info.PropertyType.IsGenericType
                    && (info.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(List<>) || info.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(Library.EquatableList<>)))
                {
                    if (!myRecursivePropertyList.Exists(delegate(string x) { return x.Equals(myObjectName + info.Name); }))
                    {
                        myPropertyStateList.Add(new PropertyState(myParentPrefix + myObjectName + info.Name, true, PropertyType.BOBaseCollection));
                        List<string> myChildRecursivePropertyList = FillDefaultRecursivePropertyList(info.PropertyType.BaseType.GetGenericArguments()[0]);
                        myChildRecursivePropertyList.AddRange(myRecursivePropertyList.FindAll(delegate(string x) { return Regex.IsMatch(x, info.Name + ".*"); }));
                        FillPropertyStateList(info.PropertyType.BaseType.GetGenericArguments()[0], ref myPropertyStateList, myParentPrefix + myObjectName, info.Name, myChildRecursivePropertyList);
                    }
                }
                else
                {
                    myPropertyStateList.Add(new PropertyState(myParentPrefix + myObjectName + info.Name, true, PropertyType.Standard));
                }

            }
            return myPropertyStateList;
        }

获取默认递归属性列表的辅助函数:

private static List<string> FillDefaultRecursivePropertyList(System.Type myObjectType)
    {
        List<string> myRecursivePropertyList = new List<string>();
        if (myObjectType.BaseType == typeof(BOBase))
        {
            System.Reflection.PropertyInfo pi = myObjectType.GetProperty("RecursivePropertyList", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
            if (pi != null)
            {
                myRecursivePropertyList = (List<string>)pi.GetValue(null, null);
            }
        }
        return myRecursivePropertyList;
    }

关于我做错了什么有什么想法吗?

【问题讨论】:

  • 为什么需要这个?我的第一直觉是,无论你想要实现什么,都必须有更好的方法,但由于我不知道你想要实现什么,所以我无法提出任何建议。
  • 另外,你为什么不直接使用调试器呢?它可以准确地告诉您无限递归发生的位置,并让您逐步找出问题所在。
  • 我需要这份清单,原因如下。我希望能够指定要实例化对象的哪些属性。我的对象的某些属性需要第二次访问数据库才能获取更多数据,有时我实际上并不需要这些数据。所以我希望能够设置不应该实例化的属性。为了做到这一点,我需要一个属性列表,其中包含一个 bool flg 值来确定该属性是否应该被“填充”。希望这有意义吗?如果有更好的方法来实现这一点,我会全力以赴。 =)
  • 另外,我使用了调试器。在开始了几个小时并没有找到解决方案之后,我决定在这里发帖看看是否有人看到我明显遗漏的东西。

标签: c# class reflection recursion properties


【解决方案1】:

我还没有深入研究代码,但是您是否考虑过使用 Attribute 来表示哪些属性是递归的?这可能会让您不必担心必须维护单独的静态属性列表。似乎列表方法可能容易出现潜在的困难同步问题。

ETA:示例代码:

如果我理解正确,这样的事情可能适用于属性级属性。它包含一个辅助方法,用于从给定类型中检索标记为递归的属性,这在构建树时可能会有所帮助。

[AttributeUsage(AttributeTargets.Property)]
public class RecursivePropertyAttribute
    : Attribute
{
    private static Dictionary<Type, List<PropertyInfo>> _Cache = new Dictionary<Type, List<PropertyInfo>>();

    public IEnumerable<PropertyInfo> GetRecursiveProperties(Type t)
    {
        // Check the cache for the type
        if (!_Cache.ContainsKey(t))
        { 
            // Create the entry
            _Cache.Add(t, new List<PropertyInfo>());

            // Add properties that have the attribute
            foreach (PropertyInfo p in t.GetProperties())
            {
                if (p.IsDefined(typeof(RecursivePropertyAttribute), true))
                    _Cache[t].Add(p);
            }
        }

        return _Cache[t];
    }
}

【讨论】:

  • 这个问题是在它自己的类中没有确定一个属性是递归的。例如,Person 的 Vendor 属性本身不是递归属性,但是 Vendor 对象的 People 属性中 Person 对象的 Vendor 属性是递归的……这有意义吗?所以我需要能够从父实例化类中设置“子”ckasses 的递归属性。
  • 在阅读了您对上述帖子的评论后,我想我对您的问题有了更好的理解。如果潜在的“递归”属性相当有限,那么重载 ctor 是否有意义?在您引用的示例中,是否有类似 Vendor() 与 Vender(Person) 的内容允许您使用提供的参数预填充属性值,或者将其保留为 null 以便在需要时延迟加载?
  • 除非我误解了您的情况(我很可能是),否则属性的递归性取决于事件链的事实与列表的静态性质是否冲突?这可能是问题吗?还是该列表只是潜在递归属性的定义?
猜你喜欢
  • 2015-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-08
  • 1970-01-01
  • 2019-07-11
  • 2020-02-02
相关资源
最近更新 更多