获取在运行时未知字段或属性名称的嵌套类的属性值

时间:2019-01-19 17:45:43

标签: c# reflection properties

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

假设:每个父类都有多个嵌套类。在下面,父项是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方法的修改版本。我使用了希思的“子属性”查找方法来获取第二级。这在第二层完美地工作。仍然需要-一种递归搜索每个子级中潜在子级的选项。

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;
    }

1 个答案:

答案 0 :(得分:0)

您知道属性类型是一个类(说实话,.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;
}