我抬头看了类似的东西,但我目前无法找到任何我能理解的东西。我从来不需要使用表达式,所以我不能真正理解它们是如何工作的,尽管它们看起来很有趣。我可以花时间研究它们,但目前我只是为了一个目的使用它们,这不是它们的设计目的,尽管我可能在这里错了。生成运行时函数以将值设置为类实例的FieldInfo。
我会用opcodes做到这一点,我更了解,但操作码并不适用于我需要使用的所有平台(即:UWP)。使用NetStandard 2.0,我可能会使用它们,但在我尝试之前,我想知道你是否可以告诉我这是否可行。目前我正在使用此代码:
public static CastedAction<T> MakeSetter(FieldInfo field)
{
if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false)
{
ParameterExpression targetExp = Expression.Parameter(typeof(T), "target");
ParameterExpression valueExp = Expression.Parameter(typeof(object), "value");
MemberExpression fieldExp = Expression.Field(targetExp, field);
UnaryExpression convertedExp = Expression.TypeAs(valueExp, field.FieldType);
BinaryExpression assignExp = Expression.Assign(fieldExp, convertedExp);
Type type = typeof(Action<,>).MakeGenericType(typeof(T), typeof(object));
var setter = Expression.Lambda(type, assignExp, targetExp, valueExp).Compile();
return new CastedAction<T>(setter);
}
throw new ArgumentException();
}
}
public class CastedAction<T>
{
readonly Action<T, object> setter;
public CastedAction(Delegate setter)
{
this.setter = (Action<T, object>)setter;
}
public CastedAction(Action<T, object> setter)
{
this.setter = setter;
}
public void Call(ref T target, object value)
{
setter(target, value); //I want to pass ref target here
//target = setter(target, value); may be an alternative
}
但是现在我想支持结构,我想要的是通过ref传递setter Action中的第一个参数。据我所知,这是不可能的。
因此我想生成一个Func,返回参数传递的修改对象。在这里,我完全迷失了,对我来说太难了。
即使您可以找到解决方案,我仍然可以考虑将100%操作码转换为返回值,并且按值传递可能会影响我的应用程序的性能。
答案 0 :(得分:1)
令人惊讶的是,这个带有自定义委托类型的简化pass-by-ref Expression
示例适用于完整框架。我完全不确定它会在没有完整Compile()
的平台上以相同的方式工作,因为你无法真正代表堆栈以外的任何地方ref T
,但......值得一试:
using System;
using System.Linq.Expressions;
using System.Runtime.Serialization;
delegate string ByRefFunc<T>(ref T val);
struct X
{
public X(string name) => Name = name;
public string Name { get; }
}
static class P
{
static void Main()
{
var p = Expression.Parameter(typeof(X).MakeByRefType(), "p");
var lambda = Expression.Lambda<ByRefFunc<X>>(
Expression.Property(p, "Name"), p);
X x = new X("abc");
var s = lambda.Compile()(ref x);
Console.WriteLine(s);
}
}
请注意,struct
副本(因为缺少ref
支持)不是世界末日,除非你有巨大的 struct
秒。
答案 1 :(得分:0)
我不明白发生了什么,但这似乎工作正常
public static CastedAction<T> MakeSetter(FieldInfo field)
{
if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false)
{
ParameterExpression targetExp = Expression.Parameter(typeof(T).MakeByRefType(), "target");
ParameterExpression valueExp = Expression.Parameter(typeof(object), "value");
MemberExpression fieldExp = Expression.Field(targetExp, field);
UnaryExpression convertedExp = Expression.TypeAs(valueExp, field.FieldType);
BinaryExpression assignExp = Expression.Assign(fieldExp, convertedExp);
var setter = Expression.Lambda<ActionRef<T, object>>(assignExp, targetExp, valueExp).Compile();
return new CastedAction<T>(setter);
}
throw new ArgumentException("<color=orange>Svelto.ECS</color> unsupported field (must be an interface and a class)");
}
public delegate void ActionRef<T, O>(ref T target, O value);
public class CastedAction<T>
{
readonly ActionRef<T, object> setter;
public CastedAction(Delegate setter)
{
this.setter = (ActionRef<T, object>)setter;
}
public CastedAction(ActionRef<T, object> setter)
{
this.setter = setter;
}
public void Call(ref T target, object value)
{
setter(ref target, value);
}
}