【问题标题】:Get Property Value of Nested Classes Where Field or Property Names are not Known at Run Time获取运行时字段或属性名称未知的嵌套类的属性值
【发布时间】:2019-06-13 15:35:53
【问题描述】:

我正在构建一个属性搜索解决方案,它允许用户在事先不知道名称的嵌套属性列表中查找每个属性名称和值。在运行时唯一已知的类对象是父类。在下面的示例中,我将父对象(atype)传递给一个方法,该方法返回(所需)所有父子成员键和值的字典。

假设:每个父类都有多个嵌套类。在下面,Parent 是 aType。当嵌套类属性的属性名称在运行时未知时,使用简单类型检索父级属性是小菜一碟,而不是嵌套类属性。

我找到的唯一解决方案是一个属性查找选项,其中完整的类路径在运行时是已知的。当类包含多个未知属性类时,这不是一个选项。一些嵌套类包含具有自己的字段和属性集的其他类属性。因此,不能对类深度做出任何假设。

期望:提供一个选项,用于在不知道嵌套类属性名称的情况下搜索父类和所有嵌套类。

public static Dictionary<string, object> DictionaryFromType(object atype)
    {
        if (atype == null) return new Dictionary<string, object>();
        var t = atype.GetType();
        var props = t.GetProperties();
        var dict = new Dictionary<string, object>();
        foreach (var prp in props)
        {
            if (prp.PropertyType.IsClass)
            {
                 // The property Names of the Nested Class are not known at 
                 // this point. This is an example.
                 // At this point I only know the property is a class. 
                 // Passing the property class name yields no result.
                    var nestedValue = GetPropertyValue(atype, "childClass.nameField");
                    if (nestedValue != null)
                    dict.Add(prp.Name, nestedValue);
            }

            var value = GetPropertyValue(atype, prp.Name);
            if (value != null)
            dict.Add(prp.Name, value);
        }
        return dict;
    }

当提供适当的对象和嵌套时,下面的工作非常好。它不会尝试查找仅提供对象名称的嵌套对象。

public static object GetPropertyValue(object obj, string propertyName)
    {
        var propertyNames = propertyName.Split('.');

        foreach (string t in propertyNames)
        {
            if (obj != null)
            {
                var propertyInfo = obj.GetType().GetProperty(t);
                if (propertyInfo != null)
                    obj = propertyInfo.GetValue(obj);
                else
                    obj = null;
            }
        }
        return obj;
    }

下面是我的 DictionaryFromType 方法的修改版本。我使用希思的子属性查找方法来获得第二级。这在第二级完美运行。仍然需要 - 递归搜索在每个 Child 中找到的潜在子类的选项。

public static Dictionary<string, object> DictionaryFromType(object atype)
    {
        if (atype == null) return new Dictionary<string, object>();
        var t = atype.GetType();
        var props = t.GetProperties();
        var dict = new Dictionary<string, object>();

        try
        {

        foreach (var prp in props)
        {
            if (prp.PropertyType.IsClass)
            {
                // The property Names of the Nested Class are not known at this point
                var nestedValue = GetNestedPropertyValue(atype, prp.Name);
                if (nestedValue == null) continue;
                var childType = nestedValue.GetType();
                // Loop through the first Sub Class of child properties
                // If this level is a Class, no properties will be returned.
                // Still Needed: A way to loop through Children of Children to see if the the Property is a Class
                foreach (var property in childType.GetProperties())
                {
                    var childTypePropertyValue = GetPropertyValue(atype, prp.Name + "." + property.Name);
                    if (!dict.ContainsKey(property.Name) && !dict.ContainsValue(childTypePropertyValue))
                    {
                        dict.Add(property.Name, childTypePropertyValue);
                    }
                }
            }
            else
            {
                    var value = GetPropertyValue(atype, prp.Name);
                    if (value != null)
                        if (!dict.ContainsKey(prp.Name) && !dict.ContainsValue(value))
                        {
                            dict.Add(prp.Name, value);
                        }
                }
        }
        return dict;

        }
        catch (Exception ex)
        {
            Log.Error("Error Building Dictionary : " + ex.Message);
        }

        return null;
    }

【问题讨论】:

  • 如果我理解您要做什么,您可以检索属性var value = GetPropertyValue(atype, prp.Name); 的值,然后使用该值递归调用您的方法 (DictionaryFromType(value)),最后合并结果字典到父目录

标签: c# reflection properties


【解决方案1】:

您知道属性类型是一个类(老实说,.NET 中的几乎所有东西都是类,包括 String),但您首先需要反映该类型并枚举其属性,例如(基本示例;使一些为简洁起见,假设并省略错误处理):

static object GetPropertyValue(object parent, string nestedPropertyName)
{
    object propertyValue = null;

    var tokens = nestedPropertyName.Split('.');
    foreach (var token in tokens)
    {
      var property = parent.GetType().GetProperty(token, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
      propertyValue = property.GetValue(parent);

      if (propertyValue is null) return null;
      parent = propertyValue;
    }

    return propertyValue;
}

【讨论】:

  • 我被卡住的地方是属性名是没有点符号的类名,因为我没有嵌套属性的集合。这让我回到了使用点符号获取属性名称列表的原始问题,这样我就可以回忆起查找,elg。 var nestedValue = GetPropertyValue(atype, prp.Name);当查找是一个类时,它看起来就像 prp.Name 中的 [className]。因此,使用 split 选项不会提供基础属性名称。
  • 那么您希望nestedPropertyName 的第一部分实际上是属性类型吗?如果多个属性属于该类型,这种情况最常发生怎么办(例如,多个字符串属性,因为字符串是一种常见的属性类型)。即便如此,如果您知道nestedPropertyName 的结构,那么请对照我的示例中的 property.PropertyType.Name 检查第一个标记,第二个标记是您从中获取值的属性名称。
  • Heath - 我借用了您的 GetPropertyValue 方法,并对我的创建字典方法进行了一些更改,我能够从父类中收集子对象名称,然后使用子对象的完全限定 propertyName完成对父 atype 的查找。这在 2 级时效果很好。如果有一个更优雅的递归选项来降低到 2 + n 级,那就太好了。无需重复相同的代码来挖掘下一个级别。您早先提到每种类型都可能是一个类,没错,但是当您向一个类提出“有一个”问题时,存在明显的区别。
  • 你不需要递归。我的解决方案支持深度嵌套的属性。请尝试使用具有深层属性的类,如果对您有帮助,请考虑将其标记为答案。
  • 我已经为上面提供了一组深度嵌套的属性,它在第 2 级停止。除非有办法设计嵌套类结构的完整路径,否则它只会看到类名并且什么都不返回。只有将完全定义的嵌套路径作为参数发送时,您的解决方案才有效。然后是如何在不知道结构有多深的情况下检索类的完整路径的问题。我认为这是该问题的部分解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 2014-06-27
  • 2019-02-03
  • 2012-01-08
  • 1970-01-01
相关资源
最近更新 更多