如何在C#中使用表达式树用只读值初始化数组中的结构
本文关键字:初始化 数组 结构 只读 表达式 | 更新日期: 2023-09-27 18:29:37
我需要使用表达式树生成代码,该树可以快速填充结构T[]
的数组,其中T包含只读字段。我需要像在GetUninitializedObject()+IL或基于反射的setters之后那样初始化它。
更新:目前看来这是不可能的。请在MS Suggestions投票支持
struct Strct
{
public readonly int Value;
}
该代码失败:
Expression.Assign(
Expression.Field(structByIndexFromArrayExp, "Value"),
deserializedValueExp)
在构建表达式树的过程中,我得到了以下错误:Expression must be writeable
从常规代码的角度来看,这完全有意义,但在反序列化过程中却没有。
FormatterServices.GetUninitializedObject()
返回一个对象,我想我需要避免它,因为它被装箱了,因此速度明显较慢。
初始化此类结构数组的最快方法是什么?
更新:目前,我看到的唯一现实的方法是动态生成结构T的克隆,但字段上没有只读属性,填充它们,修复内存中的两个数组,并进行内存复制。请投票告诉微软修复它。
反序列化并不意味着违反了语言规则。如果我尝试这个,编译器会抱怨:
void Main()
{
var a = new Foo{Bar = 1};
}
public struct Foo
{
public readonly int Bar;
}
不能期望表达式树执行代码中无法执行的操作。如果属性实际上不应该是readonly
,请删除readonly
关键字。否则,您应该有一个构造函数来初始化它
public struct Foo
{
public Foo(int bar) {this.Bar = bar;}
public readonly int Bar;
}
然后创建一个调用该构造函数的表达式,而不是直接设置字段。
实际上有一个解决方法,因为您可以使用表达式来调用反射方法。请注意,这要慢得多。
public static Expression CreateSetValueExpression(Expression target, Expression value, FieldInfo fieldInfo)
{
// workaround for readonly fields: use reflection, this is a lot slower but the only way except using il directly
if (fieldInfo.IsInitOnly)
{
MethodInfo fieldInfoSetValueMethod = typeof(FieldInfo).GetMethod("SetValue", new[] { typeof(object), typeof(object) });
return Expression.Call(Expression.Constant(fieldInfo), fieldInfoSetValueMethod, target, Expression.Convert(value, typeof(object)));
}
return Expression.Assign(Expression.Field(target, fieldInfo), value);
}