【问题标题】:Dynamically add properties to `dynamic` type动态地将属性添加到 `dynamic` 类型
【发布时间】:2015-01-11 17:20:18
【问题描述】:

如果我有一个属性信息列表,以及它们来自的对象的实例,我如何创建另一个包含这些属性和值的对象?

例如

public dynamic Sanitize<T>(T o)
{
    if (ReferenceEquals(o, null))
    {
        return null;
    }

    var type = o.GetType();

    var propertyInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

    dynamic sanitized = new ExpandoObject();

    foreach (var propertyInfo in propertyInfos)
    {
        var name = propertyInfo.Name;
        var value = propertyInfo.GetValue(o, null);

        // Add this property to `sanitized`
    }

    return sanitized;
}

【问题讨论】:

    标签: c# reflection reflection.emit system.reflection dynamic-typing


    【解决方案1】:

    您可以将 ExpandoObject 转换为 IDictionary&lt;string, object&gt;,然后在运行时对其进行操作以添加属性:

    var sanitized = new ExpandoObject() as IDictionary<string, object>;
    
    foreach (var propertyInfo in propertyInfos)
    {
        var name = propertyInfo.Name;
        var value = propertyInfo.GetValue(o, null);
        sanitized.Add(name, value);
    }
    

    【讨论】:

    • 如何从中引用属性? sanitizedType.PublicBoolTruesanitizedType["PublicBoolTrue"] 都抛出异常。
    • 您需要在哪里引用这些属性?方法里面?我宁愿把它分成两种方法。第一个将使用字典填充 ExpandoObject,如我的回答中所示,然后调用该方法,之后您将能够像所示那样引用这些属性,假设您已将此方法调用的结果存储到动态类型的变量中.否则,如果您需要在同一方法中引用该属性,您可以使用sanitized["PublicBoolTrue"]
    • 目的是为了记录日志。输入对象o 可以具有属性为[NotLoggable] 的属性,因此该方法应该返回一个仅包含“可记录”公共属性的对象。
    • 因此,将结果对象传递给的任何记录器都会引用这些属性。他们可能只是对其进行序列化,或者可能先进行一些聚合或格式化。
    • 属性将被动态添加。因此,如果您尝试访问它们,或序列化生成的对象,它将开箱即用。
    猜你喜欢
    • 1970-01-01
    • 2011-01-15
    • 2019-04-28
    • 1970-01-01
    • 2012-01-12
    • 2015-08-28
    • 1970-01-01
    相关资源
    最近更新 更多