【问题标题】:Mimic property/list changes on an object on another object在另一个对象上模拟一个对象的属性/列表更改
【发布时间】:2010-03-16 03:20:55
【问题描述】:

我需要模拟一个对象的更改(属性/列表)更改,然后将其应用于另一个对象以保持结构/属性相同。

本质上它就像克隆等。商业规则要求某些属性不能应用于另一个对象,所以我不能只克隆对象,否则这很容易。

我已经遍历源对象以获取 INotifyPropertyChanged 和 IListChanged 事件,所以我有“源”和 args(属性或列表)更改的事件通知。

鉴于我想我可以从源对象的顶层开始构建反射“层次结构路径”,以到达属性或列表更改的“源”(可能有几个层次)。

暂时忽略某些对象属性不应传播到另一个对象,构建此“路径”的方法是什么?是在顶层建立“路径”的蛮力(如果我们没有击中原始更改的事件“源”,则在返回的路上丢弃)是唯一的方法吗?

关于如何模拟从一个对象到另一个对象的变化有什么聪明的想法吗?

【问题讨论】:

  • 抱歉,它是完整的 C# 3.5(不是 silverlight)。

标签: c# reflection path hierarchy


【解决方案1】:

有一些库可让您更轻松(更快)地使用反射。例如,Fasterflect 允许您编写以下内容:

// copy only the specified named properties
source.MapProperties( target, "FirstName", "LastName" );

从您的描述看来,您需要一些递归的东西。我为 Fasterflect 编写了一个 DeepClone 方法,我相信这将为您的需求提供一个很好的起点。要修改代码,您需要将其修改为 (a) 采用目标对象参数而不是在内部创建实例,(b) 获取/设置属性而不是字段,以及 (c) 接受要包含的命名属性列表。

public static T DeepClone<T>( this T source ) where T : class, new()
{
    return source.DeepClone( null );
}

注意私有方法上的 map 参数。这使我能够跟踪创建的实例(或者在您的情况下,访问的实例),以便我们在遇到循环引用时可以做正确的事情。

private static T DeepClone<T>( this T source, Dictionary<object, object> map )
    where T : class, new()
{
    Type type = source.GetType();
    IList<FieldInfo> fields = type.Fields( Flags.StaticInstanceAnyVisibility );
    var clone = type.CreateInstance() as T;
    map = map ?? new Dictionary<object, object>();
    map[ source ] = clone;
    object[] values = fields.Select( f => GetValue( f, source, map ) ).ToArray();
    for( int i = 0; i < fields.Count; i++ )
    {
        fields[ i ].Set( clone, values[ i ] );
    }
    return clone;
}

private static object GetValue( FieldInfo field, object source, Dictionary<object, object> map )
{
    object result = field.Get( source );
    object clone;
    if( map.TryGetValue( result, out clone ) )
    {
        return clone;
    }
    bool follow = result != null && result.GetType().IsClass && result.GetType() != typeof(string);
    return follow ? result.DeepClone( map ) : result;
}

请注意,代码使用其他 Fasterflect 方法来加速实际反射,但如果您不想依赖库,那么这很容易替换。

免责声明:我作为贡献者参与了上述项目。

【讨论】:

    猜你喜欢
    • 2020-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多