具有Expression.New和Expression树的深度克隆 [英] Deep Clone with Expression.New and Expression Trees

查看:261
本文介绍了具有Expression.New和Expression树的深度克隆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个生成的接口 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 [] {m​​emberExpression});
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;

}

}

这里是一个文本模板文件,用于从EF图生成所述类


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.

Here is a gist

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆