我需要模仿对象上的更改(属性/列表)更改,然后将其应用于另一个对象以保持结构/属性不变。
本质上它就像克隆等。商业规则要求某些属性不能应用于其他对象,所以我不能只是克隆对象,否则这很容易。
我已经走过源对象来获取INotifyPropertyChanged和IListChanged事件,所以我有“源”和args(属性或列表)更改了事件通知。
鉴于我想我可以构建一个反射“层次结构路径”,从源对象的顶层开始,以获取属性或列表更改的“源”(可能是几个级别的深度)。
忽略某些对象属性不应传播到另一个对象的时刻,构建此“路径”的方法是什么?如果我们没有击中原来改变的事件“源”,那么蛮力最高级别是建立“路径”(如果我们没有击中原来改变的事件“源”那么就会丢弃)吗?
关于如何模仿从一个对象到另一个对象的变化的任何聪明的想法?
答案 0 :(得分: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方法来加速实际反射,但如果您不想依赖库,那么这很容易替换。
免责声明:我作为贡献者参与了该项目。