C# 使用扩展方法将对象属性映射到字典的最有效方法,其中键表示路径

C# 使用扩展方法将对象属性映射到字典的最有效方法,其中键表示路径,c#,reflection,C#,Reflection,扩展方法将对象属性映射到IDictionary的最有效方法是什么,其中: 键是属性路径(例如“Customer.Company.Address.Line1”) 值是属性值的字符串表示形式(例如“123 当为空或默认值时,主符号“”或“”(空字符串) 属性集合仍然只包含路径(例如。 公共IList发票-->“Customer.Invoices”,但值为 收集数量) 使用反射是最好的方法吗? 有没有一个例子 谢谢 Z 澄清更新 字典键应该是基于属性名称而不是类型层次结构的路径。因此,如果客户有

扩展方法将对象属性映射到IDictionary的最有效方法是什么,其中:

  • 键是属性路径(例如“Customer.Company.Address.Line1”)
  • 值是属性值的字符串表示形式(例如“123 当为空或默认值时,主符号“”或“”(空字符串)
  • 属性集合仍然只包含路径(例如。 公共IList发票-->“Customer.Invoices”,但值为 收集数量)
使用反射是最好的方法吗? 有没有一个例子

谢谢 Z

澄清更新
  • 字典键应该是基于属性名称而不是类型层次结构的路径。因此,如果客户有属性
    上市公司父公司
    ,而公司有属性
    公共地址计费地址
    ,则键路径应该是“父公司.计费地址”
编辑:

public static IDictionary<string, string> GetProperties<T>(this T obj)
    where T : class
{
    var properties = obj.GetPropertyList();
    return properties.ToDictionary(prop => prop.Item1, prop => prop.Item2);
}

public static IEnumerable<Tuple<string, string>> GetPropertyList<T>(this T obj)
    where T : class
{
    if (obj == null)
        throw new ArgumentNullException("obj");

    Type t = obj.GetType();

    return GetProperties(obj, t, t.Name);
}

private static IEnumerable<Tuple<string, string>> GetProperties(object obj, Type objType, string propertyPath)
{
    // If atomic property, return property value with path to property
    if (objType.IsValueType || objType.Equals(typeof(string)))
        return Enumerable.Repeat(Tuple.Create(propertyPath, obj.ToString()), 1);

    else
    {
        // Return empty value for null values
        if (obj == null)
            return Enumerable.Repeat(Tuple.Create(propertyPath, string.Empty), 1);

        else
        {
            // Recursively examine properties; add properties to property path
            return from prop in objType.GetProperties()
                   where prop.CanRead && !prop.GetIndexParameters().Any()
                   let propValue = prop.GetValue(obj, null)
                   let propType = prop.PropertyType
                   from nameValPair in GetProperties(propValue, propType, string.Format("{0}.{1}", propertyPath, prop.Name))
                   select nameValPair;
        }
    }
}
公共静态IDictionary GetProperties(此T对象)
T:在哪里上课
{
var properties=obj.GetPropertyList();
返回properties.ToDictionary(prop=>prop.Item1,prop=>prop.Item2);
}
公共静态IEnumerable GetPropertyList(此T对象)
T:在哪里上课
{
if(obj==null)
抛出新的ArgumentNullException(“obj”);
类型t=obj.GetType();
返回GetProperties(obj、t、t.Name);
}
私有静态IEnumerable GetProperties(对象obj、类型objType、字符串propertyPath)
{
//如果为原子属性,则返回属性值,路径为属性
if(objType.IsValueType | | objType.Equals(typeof(string)))
返回Enumerable.Repeat(Tuple.Create(propertyPath,obj.ToString()),1);
其他的
{
//为空值返回空值
if(obj==null)
返回Enumerable.Repeat(Tuple.Create(propertyPath,string.Empty),1);
其他的
{
//递归检查属性;将属性添加到属性路径
从objType.GetProperties()中的prop返回
其中prop.CanRead&!prop.GetIndexParameters().Any()
让propValue=prop.GetValue(obj,null)
让propType=prop.PropertyType
来自GetProperties中的nameValPair(propValue、propType、string.Format(“{0}.{1}”、propertyPath、prop.Name))
选择nameValPair;
}
}
}

这仍然不能处理值参数的默认值。请注意,何时停止递归迭代的逻辑是关键。最初,我在值类型的属性处停止,但这意味着字符串被视为其他对象。因此,我添加了一个特例,将字符串视为原子类型。

您想要完整的“属性树”作为实例吗?这是一个非常简单的反射练习。如果你有更具体的问题,你应该试着自己去实现它,然后再回来。(最有可能的是,诸如“如何获取对象的属性列表?”、“如何通过反射获取属性值?”等个别问题已经得到了回答。)我相信OP想知道是否有比反射更有效的方法(看起来他已经知道该方法)@Raphaël Althaus是的,一棵扁平的“属性树”@ananthonline,如果他已经理解了这种方法,我想OP不会要求我们给他提供一个例子,不是吗?你必须根据你的用例进行调整。例如,prop.Name还需要包含类名。再想一想,如果您想在Name字段中包含整个父类型层次结构,那么应该使用递归。名称字段是使用类型层次结构还是组合构建的?