有一些库可让您更轻松(更快)地使用反射。例如,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 方法来加速实际反射,但如果您不想依赖库,那么这很容易替换。
免责声明:我作为贡献者参与了上述项目。