在 .Net 3.5 中使用相同的签名实现 Expression.Assign
本文关键字:实现 Assign Expression Net | 更新日期: 2023-09-27 18:30:56
Expression.Assign
在.NET 4 之前不可用。我需要在此方法的 .NET 3.5 下使用原始签名实现:
public static BinaryExpression Assign(
Expression left,
Expression right
)
澄清:我不是在寻找在某些情况下使用此方法的方法。我需要实现一般情况。
由于没有ExpressionType.Assign
,因此无法获得完全相同的等价物,但可以制作类似的东西:
public static class ExpressionEx
{
public static BinaryExpression Assign(Expression left, Expression right)
{
var assign = typeof(Assigner<>).MakeGenericType(left.Type).GetMethod("Assign");
var assignExpr = Expression.Add(left, right, assign);
return assignExpr;
}
private static class Assigner<T>
{
public static T Assign(ref T left, T right)
{
return (left = right);
}
}
}
然后,您可以使用它来生成分配:
class Foo
{
public int Data
{
get;
set;
}
}
class Program
{
static Action<object, object> MakeSetter(PropertyInfo info)
{
var objectParameter = Expression.Parameter(typeof(object), string.Empty);
var valueParameter = Expression.Parameter(typeof(object), string.Empty);
var setterExpression = Expression.Lambda<Action<object, object>>(
ExpressionEx.Assign(
Expression.Property(
Expression.Convert(objectParameter, info.DeclaringType),
info),
Expression.Convert(valueParameter, info.PropertyType)),
objectParameter,
valueParameter);
return setterExpression.Compile();
}
static void Main()
{
var foo = new Foo();
var property = typeof(Foo).GetProperty("Data");
var setter = MakeSetter(property);
setter(foo, 10);
Console.WriteLine(foo.Data);
}
}
如果你真的不需要BinaryExpression
作为返回类型,你可以使用Expression.Call
而不是Add
这样它就不会那么黑客化了。
恐怕你不能。
原因如下:
-
ExpressionType
枚举不包含 3.5 中的Assign
成员。 - 我尝试使用错误的 ExpressionType 并使用
Expression.MakeBinary()
与我的方法创建一个二进制表达式,但该方法被忽略了。(生成的二进制表达式具有标准Method
或Method
= null。 - 您不能在实例中分配
Method
- 它是只读的,并且类是密封的,因此您无法在派生类中解决它。
但是由于他们已经包含了MakeBinary()
method
参数,因此可能仍然存在一些解决方法......我不是100%确定这是不可能的。
基于康斯坦丁·奥兹诺比欣(Konstantin Oznobihin)的分支,这里有一个稍微修改过的,其中包含MethodCallExpression
而不是BinaryExpression
:
public class ExpressionEx
{
public static Expression Assign(Expression left, Expression right)
{
var method = typeof(ExpressionEx).GetMethod("Assign", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(left.Type);
return Expression.Call(method, left, right);
}
private static void Assign<T>(ref T left, T right)
{
left = right;
}
}
这将在ExpressionEx
中创建 Assign
-方法的委托,现在可以像这样轻松使用:
var expr = ExpressionEx.Assign(myInstanceExpression, newValueExpression);