Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#编译表达式,用于创建新的T实例,并将值从另一个T实例复制到其属性_C#_Lambda_Reflection_Expression - Fatal编程技术网

C#编译表达式,用于创建新的T实例,并将值从另一个T实例复制到其属性

C#编译表达式,用于创建新的T实例,并将值从另一个T实例复制到其属性,c#,lambda,reflection,expression,C#,Lambda,Reflection,Expression,我想知道是否可以创建一个只在运行时才知道的类型的实例,并通过使用编译表达式为该实例的属性赋值,如果可以的话,如何实现 我有一个泛型类和一个方法,该方法接受T的一个实例并返回一个副本。T仅在运行时已知,或者更确切地说是用户/消费者定义的。我知道如何使用反射(假设在本例中它有一个空构造函数,并且没有异常处理或空检查来简化) 公共类MyClass { 公共T CreateCopy(T源) { var类型=类型(T); var copy=type.GetConstructor(type.EmptyTyp

我想知道是否可以创建一个只在运行时才知道的类型的实例,并通过使用编译表达式为该实例的属性赋值,如果可以的话,如何实现

我有一个泛型类和一个方法,该方法接受T的一个实例并返回一个副本。T仅在运行时已知,或者更确切地说是用户/消费者定义的。我知道如何使用反射(假设在本例中它有一个空构造函数,并且没有异常处理或空检查来简化)

公共类MyClass
{
公共T CreateCopy(T源)
{
var类型=类型(T);
var copy=type.GetConstructor(type.EmptyTypes).Invoke(null);
foreach(type.GetProperties()中的var pi)
{
pi.SetValue(复制,pi.GetValue(源));
}
返回副本;
}
}
反射是相当昂贵的,经过一些挖掘,我发现了一个选项,至少可以创建一个带有编译表达式的T实例

var type = typeof(T);
Expression.Lambda<Func<T>>(Expression
   .New(type.GetConstructor(Type.EmptyTypes)
       ?? throw new InvalidOperationException(
           $"Type has to have an empty public constructor. {type.Name}")))
   .Compile();
var type=typeof(T);
表达式。Lambda(表达式
.New(类型.GetConstructor(类型.EmptyTypes)
?抛出新的InvalidOperationException(
$“类型必须有一个空的公共构造函数。{Type.Name}”))
.Compile();
经过一些基准测试,我发现它的执行速度大约是CreateCopy(…)方法的6倍。问题是,我不知道哪种类型将作为泛型传入,以及它将具有多少属性。 是否有一种方法可以使用编译后的表达式执行CreateCopy(…)方法中的所有操作

我已经研究了Expression.Asign,Expression.MemberInit,但是我找不到任何合适的。Expression.MemberInit的问题在于它希望有一个Expression.BindExpression.Constant,但我无法从传递给它的T实例中获取属性值。有办法吗

多谢各位

另外,我正在寻找类似的东西:

var type = typeof(T);
var propertyInfos = type.GetProperties();
var ctor = Expression.New(type.GetConstructor(Type.EmptyTypes));
var e = Expression.Lambda<Func<T, T>>(Expression
            .MemberInit(ctor, propertyInfos.Select(pi => 
                Expression.Bind(pi, Expression.Constant(pi.GetValue(source)))))).Compile();
var type=typeof(T);
var propertyInfos=type.GetProperties();
var-ctor=Expression.New(type.GetConstructor(type.EmptyTypes));
var e=表达式.Lambda(表达式
.MemberInit(ctor,propertyInfos.Select(pi=>
Expression.Bind(pi,Expression.Constant(pi.GetValue(source‘‘‘‘‘)’).Compile();

你就快到了。您需要定义一个参数,然后使用属性访问表达式指定属性,如下所示:

public static T Express<T>(T source)
{
   var parameter = Expression.Parameter(typeof(T), "source");
   var type = typeof(T);
   var ctor = Expression
              .New(type.GetConstructor(Type.EmptyTypes));
   var propertyInfos = type.GetProperties();
   var e = Expression
            .Lambda<Func<T, T>>(
              Expression
              .MemberInit(ctor, propertyInfos.Select(pi =>
                   Expression.Bind(pi, CanBeAssigned(pi.PropertyType)
                    ? (Expression)Expression.Property(parameter, pi.Name)
                    : Expression.Call(typeof(Program).GetMethod(nameof(Express))
                                   .MakeGenericMethod(pi.PropertyType),                                                                        
                                  Expression.Property(parameter, pi.Name)
                          ))
                 )),
                parameter
            );
            var x = e.Compile();
            var z = x(source);
            return z;
}

public static bool CanBeAssigned(Type t)
{
    return t.IsValueType || t.Name == "String"; // this might need some improvements
}
公共静态T Express(T源)
{
var参数=表达式参数(类型(T),“源”);
var类型=类型(T);
变量=表达式
.New(type.GetConstructor(type.EmptyTypes));
var propertyInfos=type.GetProperties();
var e=表达式
兰姆达先生(
表情
.MemberInit(ctor,propertyInfos.Select(pi=>
Expression.Bind(pi,CanBeAssigned(pi.PropertyType)
?(表达式)表达式属性(参数,pi.Name)
:Expression.Call(typeof(Program).GetMethod(nameof(Express))
.MakeGenericMethod(pi.PropertyType),
Expression.Property(参数,pi.Name)
))
)),
参数
);
var x=e.Compile();
var z=x(来源);
返回z;
}
可指定公共静态布尔值(t型)
{
返回t.IsValueType | | t.Name==“String”//这可能需要一些改进
}

你就快到了。您需要定义一个参数,然后使用属性访问表达式指定属性,如下所示:

public static T Express<T>(T source)
{
   var parameter = Expression.Parameter(typeof(T), "source");
   var type = typeof(T);
   var ctor = Expression
              .New(type.GetConstructor(Type.EmptyTypes));
   var propertyInfos = type.GetProperties();
   var e = Expression
            .Lambda<Func<T, T>>(
              Expression
              .MemberInit(ctor, propertyInfos.Select(pi =>
                   Expression.Bind(pi, CanBeAssigned(pi.PropertyType)
                    ? (Expression)Expression.Property(parameter, pi.Name)
                    : Expression.Call(typeof(Program).GetMethod(nameof(Express))
                                   .MakeGenericMethod(pi.PropertyType),                                                                        
                                  Expression.Property(parameter, pi.Name)
                          ))
                 )),
                parameter
            );
            var x = e.Compile();
            var z = x(source);
            return z;
}

public static bool CanBeAssigned(Type t)
{
    return t.IsValueType || t.Name == "String"; // this might need some improvements
}
公共静态T Express(T源)
{
var参数=表达式参数(类型(T),“源”);
var类型=类型(T);
变量=表达式
.New(type.GetConstructor(type.EmptyTypes));
var propertyInfos=type.GetProperties();
var e=表达式
兰姆达先生(
表情
.MemberInit(ctor,propertyInfos.Select(pi=>
Expression.Bind(pi,CanBeAssigned(pi.PropertyType)
?(表达式)表达式属性(参数,pi.Name)
:Expression.Call(typeof(Program).GetMethod(nameof(Express))
.MakeGenericMethod(pi.PropertyType),
Expression.Property(参数,pi.Name)
))
)),
参数
);
var x=e.Compile();
var z=x(来源);
返回z;
}
可指定公共静态布尔值(t型)
{
返回t.IsValueType | | t.Name==“String”//这可能需要一些改进
}

正如您所知,这对任何任意类型都不起作用,在生产代码中似乎是一件相当危险的事情。正如您所知,这对任何任意类型都不起作用,在生产代码中似乎是一件相当危险的事情。谢谢!2个问题:1)您已经创建了´´´var props=propertyInfos.Select(r=>Expression.Property(ctor,r.Name));但它从未被使用过。这是干什么用的?2) “浅复制”的意思是,如果属性本身是引用类型,那么只复制一个引用,或者?@Apolonius好吧,第一个是输入错误,我已经内联了,忘了删除它,第二个是,它只复制引用类型对象的引用。这澄清了这一点。非常感谢你。我的错误是没有像下面的表达式那样给Lambda赋予“parameter”。Lambda(…,parameter);如此接近,但迄今为止:)@Apolonius更新的答案,以处理深度清洁(ish)方案。谢谢!2个问题:1)哟