具有Expression.New和Expression树的深度克隆 [英] Deep Clone with Expression.New and Expression Trees
问题描述
我有两个生成的接口 IPerson
和 IAddress
。
但是我定义了从那些基本接口继承的属性接口
接口
公共接口IPerson_Name:IPerson {字符串名称{get; set;}}
公共接口IPerson_Addresses:IPerson
{
ICollection< IAddress>地址{get;组; }
IAddress NewAddress();
}
公共接口IAddress_Line1:IAddress
{
字符串Line1 {get;组; }
}
然后,我对每个基本接口都有两种实现方式
实施
公共类人员:IPerson
{
公共字符串名称{get;组; }
public ICollection< Address>地址{get;组; }
}
公共类PersonPoco:IPerson_Name,IPerson_Addresses
{
公共字符串Name {get;组; }
public ICollection< IAddress>地址{get;组; }
public IAddress NewAddress()
{
return new AddressPoco();
}
}
公共类地址:IAddress
{
public String Line1 {get;组; }
}
公共类AddressPoco:IAddress_Line1
{
public String Line1 {get;组; }
}
我正在尝试构建表达式树,以便在PersonPoco和Person之间转换为以及任何其他IPerson
我正在这样创建一个CopyTo函数。
复制扩展
公共静态类IPersonExt
{
公共静态IQueryable< TDest> CopyTo< TSrc,TDest>(此IQueryable< TSrc>人员)
其中TSrc:IPerson,new()
其中TDest:IPerson,new()
{
var innerLambda =(LambdaExpression)CopyTo(typeof(TSrc),typeof(TDest));
var copyExpr = Expression.Lambda< Func< TSrc,TDest>>(innerLambda.Body,innerLambda.Parameters);
返回人员。Select(copyExpr);
}
内部静态LambdaExpression CopyTo(Type tSrc,类型tDest)
{
var dest = Activator.CreateInstance(tDest);
var personparam = Expression.Parameter(tSrc);
var destNewExpr = Expression.New(tDest);
var memberbindings = new List< MemberBinding>();
IPerson_Name destName;
IPerson_Name srcName;
if(((tDest.IsInstanceOfType(typeof(IPerson_Name))|| tDest.IsInstanceOfType(typeof(Person))))&&
(tSrc.IsInstanceOfType(typeof(IPerson_Name))|| tSrc。 IsInstanceOfType(typeof(Person))))
{
memberbindings.Add(Expression.Bind(tDest.GetProperty( Name),Expression.Property(personparam, Name))));;
}
var toEntityParameterExpression = Expression.MemberInit(destNewExpr,memberbindings);
返回Expression.Lambda(
toEntityParameterExpression,
personparam
);
}
}
我的目的是为每个实现保存编译后的输出到IPerson和IAddress的实现转换。 -framework-iqueryable-with-poco-generation>这个问题
编辑
I将基本参数复制到新版本。到目前为止,它可以用于基本属性。我已经更新了上面的代码
编辑:显然,对实体的linq无法理解这些表达式中的方法调用。因此这没有帮助。
实现以下接口的接口将能够复制其公共接口的属性。
公共接口IEntity
{
}
公共接口IEntityObject:IEntity
{
}
公共接口IEntityCollection:IEntity
{
}
公共接口IEntityProperty:IEntity
{
}
然后,对于实体的每个属性,您需要创建一个接口
公共接口IThing:IEntity {}
公共接口IThing_Property:IThing,IEntityProperty
{
int SimpleProperty {get; set;}
}
公共接口IThing_ComplexProperty:IThing,IEntityObject {}
公共接口IThing_ComplexProperty< T> :IEntity_ComplexProperty其中T:class,IEntity,new()
{
T SomeProperty {get; set;}
}
公共接口IThing_CollectionProperty:IThing,IEntityCollection {}
公共接口IThing_CollectionProperty< T> :IEntity_CollectionProperty,其中T:class,IEntity,new()
{
IEnumerable< T> SomeCollectionProperty {get; set;}
}
现在就可以了
IQueryable< SomeThingImpl> X;
IQueryable< SomeOtherThingImpl> y = x.CopyTo< SomeThingImpl,SomeOtherThingImpl>()
直到我还没有被叫到
此外,如果泛型类型共享任何IEntity接口,它们也将被复制。
这是类的样子
公共静态类CopyToExt
{
private静态只读ConcurrentDictionary< Type,LambdaExpression>表情;
私有静态只读ConcurrentDictionary< Type,Object>功能
私有静态只读ConcurrentDictionary< Type,LambdaExpression> mergeStackExpr;
private static ConcurrentDictionary< Type,Object> mergeStackFunc;
public static MethodInfo AsQueryableMethod;
public static MethodInfo SelectMethod;
public static MethodInfo ToListMethod;
public static MethodInfo CopyToMethod;
public static MethodInfo AddMergeMethod;
public static MethodInfo CreateMergeMethod;
public static MethodInfo TryCopyMethod;
静态CopyToExt()
{
mergeStackExpr = new ConcurrentDictionary< Type,LambdaExpression>(new Dictionary< Type,LambdaExpression>());
foreach(typeof(Queryable).GetMethods()。Where(m => m.Name == Select)中的MethodInfo m)
foreach(m.GetParameters()中的ParameterInfo p (p => p.Name.Equals( selector)))
if(p.ParameterType.GetGenericArguments()。Any(x => x.GetGenericArguments()。Count()== 2) )
SelectMethod =(MethodInfo)p.Member;
foreach(typeof(Enumerable).GetMethods()。Where(m => m.Name == ToList)中的MethodInfo m)
foreach(m.GetParameters()中的ParameterInfo p (p => p.Name.Equals(源)))
如果(p.ParameterType.GetGenericArguments()。Count()== 1)
ToListMethod =(MethodInfo)p.Member ;
foreach(typeof(Queryable).GetMethods()。Where(m => m.Name == AsQueryable)中的MethodInfo m)
foreach(m.GetParameters()中的ParameterInfo p (p => p.Name.Equals(源)))
如果(p.ParameterType.GetGenericArguments()。Count()== 1)
AsQueryableMethod =(MethodInfo)p.Member ;
CreateMergeMethod = typeof(CopyToExt).GetMethods()。First(m => m.Name == CreateMergeStack);
AddMergeMethod = typeof(MergeStack).GetMethods()。First(m => m.Name == AddReturnOrCreateAddReturn);
TryCopyMethod = typeof(MergeStack).GetMethods()。First(m => m.Name == TryCopy);
}
公共静态IQueryable< TDest> CopyTo< TSrc,TDest>(此IQueryable< TSrc>可查询)
其中TSrc:类,IEntity
其中TDest:类,IEntity
{
var copyExpr = CreateTryCopy< TSrc, TDest>();
var ms = CreateMergeStack< TSrc>();
返回queryable.Select(ms).Select(copyExpr);
}
公共静态IEnumerable< TDest> CopyTo< TSrc,TDest>(此IEnumerable< TSrc>可查询)
其中TSrc:class,IEntity
其中TDest:class,IEntity
{
返回queryable.AsQueryable()。 CopyTo< TSrc,TDest>()。AsEnumerable();
}
公共静态表达式< Func< TSrc,Stackholder< TSrc>> CreateMergeStack< TSrc>()
{
返回mergeStackExpr.GetOrAdd(typeof(TSrc),(type)=>
{
var shtype = typeof(Stackholder< TSrc>) ;
var parm = Expression.Parameter(typeof(TSrc));
var destNewExpr = Expression.New(shtype);
var methodcall = Expression.Call(null,
CopyToExt .AddMergeMethod);
var memInit = Expression.MemberInit(destNewExpr,
Expression.Bind(shtype.GetField( Src),parm),
Expression.Bind(shtype .GetField( Ms),methodcall));
返回Expression.Lambda< Func< TSrc,Stackholder< TSrc>>>(memInit,parm);
})作为Expression< Func< TSrc,Stackholder< TSrc>> ;;
}
公共静态表达式< Func< Stackholder< TSrc> ;, TDest> CreateTryCopy< TSrc,TDest>()
{
var shtype = typeof(Stackholder< TSrc>);;
var parentParam = Expression.Parameter(shtype);
var SrcExpr = Expression.PropertyOrField(parentParam, Src);
var MSExpr = Expression.PropertyOrField(parentParam, Ms);
var tcMethod = Expression.Call(MSExpr,
TryCopyMethod.MakeGenericMethod(new Type [] {typeof(TSrc),typeof(TDest)}),
SrcExpr);
return Expression.Lambda< Func< Stackholder< TSrc> ;, TDest>>(tcMethod,parentParam);
}
内部静态布尔隐含(此类型,类型InheritedType)
{
return(type.IsSubclassOf(inheritedType)|| type.GetInterface(inheritedType。 FullName)!= null);
}
内部静态布尔隐式T(此Type类型,TypeInheritedType = null)
{
返回type.Impliments(typeof(T));
}
私有静态ConcurrentDictionary< Type,Object> AssignDict =
new ConcurrentDictionary< Type,Object>(new Dictionary< Type,Object>());
内部静态Func< TSrc,TDest,MergeStack,TDest> Assign< TSrc,TDest>()
{
return(Func< TSrc,TDest,MergeStack,TDest>)AssignDict.GetOrAdd(typeof(Func< TSrc,TDest>),(indexType)=>
{
var tSrc = typeof(TSrc);
var tDest = typeof(TDest);
srcEntityInterfaces = tSrc.GetInterfaces()。Where(x => x。隐式< IEntity>());
var destEntityInterfaces = tDest.GetInterfaces()。Where(x => x.Imppliments< IEntity>());
var srcParam = Expression.Parameter(tSrc) ;
var destParam = Expression.Parameter(tDest);
var MSExpr = Expression.Parameter(typeof(MergeStack));
var common = destEntityInterfaces.Intersect (srcEntityInterfaces);
var memberbindings = common.Where(x => x.Imppliments< IEntityProperty>())
.Select(type => type.GetProperties()。 ())
.Select(
道具=>
Expression.Assign(Expression.Property(destParam,prop.Name),
Expression.Property(srcParam,prop.Name)))
.Cast< Expression>()。ToList() ;
foreach(共同的var类型。where(x => x.Imppliments< IEntityObject>()))
{
var destSubType = destEntityInterfaces.First (x => x.Imppliments(type))
.GetGenericArguments()
.First();
var srcSubType = srcEntityInterfaces.First(x => x.Imppliments(type))
.GetGenericArguments()
.First();
var dProp = destEntityInterfaces.First(x => x.Impliments(type))。GetProperties()。First();
var sProp = srcEntityInterfaces.First(x => x.Impliments(type))。GetProperties()。First();
var tcParam = Expression.Parameter(srcSubType);
var tcMethod = Expression.Call(MSExpr,
TryCopyMethod.MakeGenericMethod(new Type [] {srcSubType,destSubType}),
tcParam);
LambdaExpression mergeLambda = Expression.Lambda(tcMethod,tcParam);
MemberExpression memberExpression = Expression.Property(srcParam,sProp.Name);
InvocationExpression invocationExpression = Expression.Invoke(mergeLambda,
Expression.Property(srcParam,sProp.Name));
var check = Expression.Condition(
Expression.MakeBinary(ExpressionType.NotEqual,memberExpression,
Expression.Constant(null,sProp.PropertyType)),invocationExpression,
Expression.Constant (null,invocationExpression.Type));
BinaryExpression binaryExpression = Expression.Assign(Expression.Property(destParam,dProp.Name),
检查);
memberbindings.Add(binaryExpression);
}
foreach(通用变量类型,其中(x => x.Imppliments< IEntityCollection>()))
{
var destSubType = destEntityInterfaces。 First(x => x.Imppliments(type))
.GetGenericArguments()
.First();
var srcSubType = srcEntityInterfaces.First(x => x.Imppliments(type))
.GetGenericArguments()
.First();
var dProp = destEntityInterfaces.First(x => x.Impliments(type))。GetProperties()。First();
var sProp = srcEntityInterfaces.First(x => x.Impliments(type))。GetProperties()。First();
var tcParam = Expression.Parameter(srcSubType);
var tcMethod = Expression.Call(MSExpr,
TryCopyMethod.MakeGenericMethod(new Type [] {srcSubType,destSubType}),
tcParam);
LambdaExpression mergeLambda = Expression.Lambda(tcMethod,tcParam);
var memberExpression = Expression.Property(srcParam,sProp.Name);
var selectExpr = Expression.Call(null,
AsQueryableMethod.MakeGenericMethod(new Type [] {srcSubType}),
new Expression [] {memberExpression});
selectExpr = Expression.Call(null,
CopyToExt.SelectMethod.MakeGenericMethod(new Type [] {srcSubType,destSubType}),
new Expression [] {selectExpr,mergeLambda});
selectExpr = Expression.Call(null,
CopyToExt.ToListMethod.MakeGenericMethod(new Type [] {destSubType}),
new Expression [] {selectExpr});
var check = Expression.Condition(
Expression.MakeBinary(ExpressionType.NotEqual,memberExpression,
Expression.Constant(null,sProp.PropertyType)),selectExpr ,
Expression.Constant(null,selectExpr.Type));
memberbindings.Add(Expression.Assign(Expression.Property(destParam,dProp.Name),check));
}
memberbindings.Add(destParam);
返回
Expression.Lambda< Func< TSrc,TDest,MergeStack,TDest>>(Expression.Block(memberbindings),
new ParameterExpression [] {srcParam,destParam,MSExpr})。 Compile();
});
}
}
公共类Stackholder< TSrc>
{
公共MergeStack女士;
公共TSrc Src;
}
公共类MergeStack
{
private static ConcurrentDictionary< Thread,MergeStack> StackDict =新的ConcurrentDictionary< Thread,MergeStack>(new Dictionary< Thread,MergeStack>());
private只读Dictionary< Type,Dictionary< Object,Object>> _mergeObjDict = new字典< Type,字典< object,object>>();
公共静态MergeStack AddReturnOrCreateAddReturn()
{
return StackDict.GetOrAdd(Thread.CurrentThread,(x)=> new MergeStack(){});
}
public TDest TryCopy< TSrc,TDest>(TSrc Src)
其中TSrc:class,IEntity
其中TDest:class,IEntity,new()
{
if(Src == null)返回null;
var objToIndex = new TDest();
字典< object,object> objToObj;
if(!_mergeObjDict.ContainsKey(objToIndex.GetType()))
{
objToObj = new字典< object,object>();
_mergeObjDict.Add(objToIndex.GetType(),objToObj);
}
else
{
objToObj = _mergeObjDict [objToIndex.GetType()];
}
if(!objToObj.ContainsKey(Src))
{
objToObj.Add(Src,objToIndex);
返回CopyToExt.Assign< TSrc,TDest>()(Src,objToIndex,this);
}
返回objToObj [Src]作为TDest;
}
}
I have two Generated Interfaces IPerson
and IAddress
.
However I have defined Property Interfaces which Inherit from those base Interfaces
Interfaces
public interface IPerson_Name : IPerson { String Name{get;set;}}
public interface IPerson_Addresses : IPerson
{
ICollection<IAddress> Addresses{ get; set; }
IAddress NewAddress();
}
public interface IAddress_Line1 : IAddress
{
String Line1 { get; set; }
}
Then I have two implementations of each of the base interfaces
Implementation
public class Person : IPerson
{
public String Name { get; set; }
public ICollection<Address> Addresses { get; set; }
}
public class PersonPoco : IPerson_Name, IPerson_Addresses
{
public string Name { get; set; }
public ICollection<IAddress> Addresses { get; set; }
public IAddress NewAddress()
{
return new AddressPoco();
}
}
public class Address : IAddress
{
public String Line1 { get; set; }
}
public class AddressPoco : IAddress_Line1
{
public String Line1 { get; set; }
}
I'm trying to build expression trees to Convert between PersonPoco and Person as well as any other IPerson
I'm creating a CopyTo function as such.
Copy Extenstion
public static class IPersonExt
{
public static IQueryable<TDest> CopyTo<TSrc,TDest>(this IQueryable<TSrc> persons)
where TSrc : IPerson, new()
where TDest: IPerson, new()
{
var innerLambda = (LambdaExpression)CopyTo(typeof (TSrc), typeof (TDest));
var copyExpr = Expression.Lambda<Func<TSrc, TDest>>(innerLambda.Body, innerLambda.Parameters);
return persons.Select(copyExpr);
}
internal static LambdaExpression CopyTo(Type tSrc, Type tDest)
{
var dest = Activator.CreateInstance(tDest);
var personparam = Expression.Parameter(tSrc);
var destNewExpr = Expression.New(tDest);
var memberbindings = new List<MemberBinding>();
IPerson_Name destName;
IPerson_Name srcName;
if ((tDest.IsInstanceOfType(typeof(IPerson_Name)) || tDest.IsInstanceOfType(typeof(Person))) &&
(tSrc.IsInstanceOfType(typeof(IPerson_Name)) || tSrc.IsInstanceOfType(typeof(Person))))
{
memberbindings.Add(Expression.Bind(tDest.GetProperty("Name"), Expression.Property(personparam, "Name")));
}
var toEntityParameterExpression = Expression.MemberInit(destNewExpr, memberbindings);
return Expression.Lambda(
toEntityParameterExpression,
personparam
);
}
}
My intention is to save the compiled output for every implementation to implementation conversion of IPerson and IAddress.
If you want more info about my intentions see this question
Edit
I got the base parameter copying to a new version. It's working so far for basic properties. I've updated the code above
EDIT: Apparently linq to entities can't understand the method calls in these expressions. so this is no help.
Interface that Implements the following interface will be able to copy properties of their common interfaces.
public interface IEntity
{
}
public interface IEntityObject : IEntity
{
}
public interface IEntityCollection : IEntity
{
}
public interface IEntityProperty : IEntity
{
}
Then for each property of an entity, you need to create an interface
public interface IThing:IEntity{}
public interface IThing_Property: IThing, IEntityProperty
{
int SimpleProperty{get;set;}
}
public interface IThing_ComplexProperty: IThing, IEntityObject{}
public interface IThing_ComplexProperty<T> : IEntity_ComplexProperty where T:class, IEntity,new()
{
T SomeProperty{get;set;}
}
public interface IThing_CollectionProperty: IThing, IEntityCollection{}
public interface IThing_CollectionProperty<T> :IEntity_CollectionProperty where T:class, IEntity,new()
{
IEnumerable<T> SomeCollectionProperty{get;set;}
}
Now if you do
IQueryable<SomeThingImpl> x;
IQueryable<SomeOtherThingImpl> y = x.CopyTo<SomeThingImpl,SomeOtherThingImpl>()
I will not have been called yet until it enumerates.
Also if The generics types share any IEntity Interfaces, they too will be copied over.
For a fuller implementation here's another gist
Here's what the classes look like
public static class CopyToExt
{
private static readonly ConcurrentDictionary<Type, LambdaExpression> expressions;
private static readonly ConcurrentDictionary<Type, Object> funcs;
private static readonly ConcurrentDictionary<Type, LambdaExpression> mergeStackExpr;
private static ConcurrentDictionary<Type, Object> mergeStackFunc;
public static MethodInfo AsQueryableMethod;
public static MethodInfo SelectMethod;
public static MethodInfo ToListMethod;
public static MethodInfo CopyToMethod;
public static MethodInfo AddMergeMethod;
public static MethodInfo CreateMergeMethod;
public static MethodInfo TryCopyMethod;
static CopyToExt()
{
mergeStackExpr = new ConcurrentDictionary<Type, LambdaExpression>(new Dictionary<Type, LambdaExpression>());
foreach (MethodInfo m in typeof(Queryable).GetMethods().Where(m => m.Name == "Select"))
foreach (ParameterInfo p in m.GetParameters().Where(p => p.Name.Equals("selector")))
if (p.ParameterType.GetGenericArguments().Any(x => x.GetGenericArguments().Count() == 2))
SelectMethod = (MethodInfo)p.Member;
foreach (MethodInfo m in typeof(Enumerable).GetMethods().Where(m => m.Name == "ToList"))
foreach (ParameterInfo p in m.GetParameters().Where(p => p.Name.Equals("source")))
if (p.ParameterType.GetGenericArguments().Count() == 1)
ToListMethod = (MethodInfo)p.Member;
foreach (MethodInfo m in typeof(Queryable).GetMethods().Where(m => m.Name == "AsQueryable"))
foreach (ParameterInfo p in m.GetParameters().Where(p => p.Name.Equals("source")))
if (p.ParameterType.GetGenericArguments().Count() == 1)
AsQueryableMethod = (MethodInfo)p.Member;
CreateMergeMethod = typeof(CopyToExt).GetMethods().First(m => m.Name == "CreateMergeStack");
AddMergeMethod = typeof(MergeStack).GetMethods().First(m => m.Name == "AddReturnOrCreateAddReturn");
TryCopyMethod = typeof(MergeStack).GetMethods().First(m => m.Name == "TryCopy");
}
public static IQueryable<TDest> CopyTo<TSrc, TDest>(this IQueryable<TSrc> queryable)
where TSrc : class, IEntity
where TDest : class, IEntity
{
var copyExpr = CreateTryCopy<TSrc, TDest>();
var ms = CreateMergeStack<TSrc>();
return queryable.Select(ms).Select(copyExpr);
}
public static IEnumerable<TDest> CopyTo<TSrc, TDest>(this IEnumerable<TSrc> queryable)
where TSrc : class, IEntity
where TDest : class, IEntity
{
return queryable.AsQueryable().CopyTo<TSrc, TDest>().AsEnumerable();
}
public static Expression<Func<TSrc, Stackholder<TSrc>>> CreateMergeStack<TSrc>()
{
return mergeStackExpr.GetOrAdd(typeof(TSrc), (type) =>
{
var shtype = typeof(Stackholder<TSrc>);
var parm = Expression.Parameter(typeof(TSrc));
var destNewExpr = Expression.New(shtype);
var methodcall = Expression.Call(null,
CopyToExt.AddMergeMethod);
var memInit = Expression.MemberInit(destNewExpr,
Expression.Bind(shtype.GetField("Src"), parm),
Expression.Bind(shtype.GetField("Ms"), methodcall));
return Expression.Lambda<Func<TSrc, Stackholder<TSrc>>>(memInit, parm);
}) as Expression<Func<TSrc, Stackholder<TSrc>>>;
}
public static Expression<Func<Stackholder<TSrc>, TDest>> CreateTryCopy<TSrc, TDest>()
{
var shtype = typeof(Stackholder<TSrc>);
var parentParam = Expression.Parameter(shtype);
var SrcExpr = Expression.PropertyOrField(parentParam, "Src");
var MSExpr = Expression.PropertyOrField(parentParam, "Ms");
var tcMethod = Expression.Call(MSExpr,
TryCopyMethod.MakeGenericMethod(new Type[] { typeof(TSrc), typeof(TDest) }),
SrcExpr);
return Expression.Lambda<Func<Stackholder<TSrc>, TDest>>(tcMethod, parentParam);
}
internal static bool Impliments(this Type type, Type inheritedType)
{
return (type.IsSubclassOf(inheritedType) || type.GetInterface(inheritedType.FullName) != null);
}
internal static bool Impliments<T>(this Type type, Type inheritedType = null)
{
return type.Impliments(typeof(T));
}
private static ConcurrentDictionary<Type, Object> AssignDict =
new ConcurrentDictionary<Type, Object>(new Dictionary<Type, Object>());
internal static Func<TSrc, TDest, MergeStack, TDest> Assign<TSrc, TDest>()
{
return (Func<TSrc, TDest, MergeStack, TDest>) AssignDict.GetOrAdd(typeof (Func<TSrc, TDest>), (indexType) =>
{
var tSrc = typeof (TSrc);
var tDest = typeof (TDest);
var srcEntityInterfaces = tSrc.GetInterfaces().Where(x => x.Impliments<IEntity>());
var destEntityInterfaces = tDest.GetInterfaces().Where(x => x.Impliments<IEntity>());
var srcParam = Expression.Parameter(tSrc);
var destParam = Expression.Parameter(tDest);
var MSExpr = Expression.Parameter(typeof (MergeStack));
var common = destEntityInterfaces.Intersect(srcEntityInterfaces);
var memberbindings = common.Where(x => x.Impliments<IEntityProperty>())
.Select(type => type.GetProperties().First())
.Select(
prop =>
Expression.Assign(Expression.Property(destParam, prop.Name),
Expression.Property(srcParam, prop.Name)))
.Cast<Expression>().ToList();
foreach (var type in common.Where(x => x.Impliments<IEntityObject>()))
{
var destSubType = destEntityInterfaces.First(x => x.Impliments(type))
.GetGenericArguments()
.First();
var srcSubType = srcEntityInterfaces.First(x => x.Impliments(type))
.GetGenericArguments()
.First();
var dProp = destEntityInterfaces.First(x => x.Impliments(type)).GetProperties().First();
var sProp = srcEntityInterfaces.First(x => x.Impliments(type)).GetProperties().First();
var tcParam = Expression.Parameter(srcSubType);
var tcMethod = Expression.Call(MSExpr,
TryCopyMethod.MakeGenericMethod(new Type[] {srcSubType, destSubType}),
tcParam);
LambdaExpression mergeLambda = Expression.Lambda(tcMethod, tcParam);
MemberExpression memberExpression = Expression.Property(srcParam, sProp.Name);
InvocationExpression invocationExpression = Expression.Invoke(mergeLambda,
Expression.Property(srcParam, sProp.Name));
var check = Expression.Condition(
Expression.MakeBinary(ExpressionType.NotEqual, memberExpression,
Expression.Constant(null, sProp.PropertyType)), invocationExpression,
Expression.Constant(null, invocationExpression.Type));
BinaryExpression binaryExpression = Expression.Assign(Expression.Property(destParam, dProp.Name),
check);
memberbindings.Add(binaryExpression);
}
foreach (var type in common.Where(x => x.Impliments<IEntityCollection>()))
{
var destSubType = destEntityInterfaces.First(x => x.Impliments(type))
.GetGenericArguments()
.First();
var srcSubType = srcEntityInterfaces.First(x => x.Impliments(type))
.GetGenericArguments()
.First();
var dProp = destEntityInterfaces.First(x => x.Impliments(type)).GetProperties().First();
var sProp = srcEntityInterfaces.First(x => x.Impliments(type)).GetProperties().First();
var tcParam = Expression.Parameter(srcSubType);
var tcMethod = Expression.Call(MSExpr,
TryCopyMethod.MakeGenericMethod(new Type[] {srcSubType, destSubType}),
tcParam);
LambdaExpression mergeLambda = Expression.Lambda(tcMethod, tcParam);
var memberExpression = Expression.Property(srcParam, sProp.Name);
var selectExpr = Expression.Call(null,
AsQueryableMethod.MakeGenericMethod(new Type[] {srcSubType}),
new Expression[] {memberExpression});
selectExpr = Expression.Call(null,
CopyToExt.SelectMethod.MakeGenericMethod(new Type[] {srcSubType, destSubType}),
new Expression[] {selectExpr, mergeLambda});
selectExpr = Expression.Call(null,
CopyToExt.ToListMethod.MakeGenericMethod(new Type[] {destSubType}),
new Expression[] {selectExpr});
var check = Expression.Condition(
Expression.MakeBinary(ExpressionType.NotEqual, memberExpression,
Expression.Constant(null, sProp.PropertyType)), selectExpr,
Expression.Constant(null, selectExpr.Type));
memberbindings.Add(Expression.Assign(Expression.Property(destParam, dProp.Name), check));
}
memberbindings.Add(destParam);
return
Expression.Lambda<Func<TSrc, TDest, MergeStack, TDest>>(Expression.Block(memberbindings),
new ParameterExpression[] {srcParam, destParam, MSExpr}).Compile();
});
}
}
public class Stackholder<TSrc>
{
public MergeStack Ms;
public TSrc Src;
}
public class MergeStack
{
private static ConcurrentDictionary<Thread, MergeStack> StackDict = new ConcurrentDictionary<Thread, MergeStack>(new Dictionary<Thread, MergeStack>());
private readonly Dictionary<Type, Dictionary<Object, Object>> _mergeObjDict = new Dictionary<Type, Dictionary<object, object>>();
public static MergeStack AddReturnOrCreateAddReturn()
{
return StackDict.GetOrAdd(Thread.CurrentThread, (x) => new MergeStack() { });
}
public TDest TryCopy<TSrc, TDest>(TSrc Src)
where TSrc : class, IEntity
where TDest : class, IEntity, new()
{
if (Src == null) return null;
var objToIndex = new TDest();
Dictionary<object, object> objToObj;
if (!_mergeObjDict.ContainsKey(objToIndex.GetType()))
{
objToObj = new Dictionary<object, object>();
_mergeObjDict.Add(objToIndex.GetType(), objToObj);
}
else
{
objToObj = _mergeObjDict[objToIndex.GetType()];
}
if (!objToObj.ContainsKey(Src))
{
objToObj.Add(Src, objToIndex);
return CopyToExt.Assign<TSrc, TDest>()(Src, objToIndex, this);
}
return objToObj[Src] as TDest;
}
}
Here is a text template file to generate said classes from an EF diagram
这篇关于具有Expression.New和Expression树的深度克隆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!