C# 如何使用C语言中的表达式树,用只读值初始化数组中的结构#
我需要使用表达式树生成代码,它可以快速填充结构数组C# 如何使用C语言中的表达式树,用只读值初始化数组中的结构#,c#,.net,serialization,expression-trees,C#,.net,Serialization,Expression Trees,我需要使用表达式树生成代码,它可以快速填充结构数组T[],其中T包含一个只读字段。我需要像在GetUninitializedObject()+IL或基于反射的setter之后一样初始化它 更新:目前看来这是不可能的。请 此代码失败: Expression.Assign( Expression.Field(structByIndexFromArrayExp, "Value"), deserializedValueExp) 在表达式树构造过程中,我遇到以下错误:表达式必须是可写的
T[]
,其中T包含一个只读字段。我需要像在GetUninitializedObject()+IL或基于反射的setter之后一样初始化它
更新:目前看来这是不可能的。请
此代码失败:
Expression.Assign(
Expression.Field(structByIndexFromArrayExp, "Value"),
deserializedValueExp)
在表达式树构造过程中,我遇到以下错误:表达式必须是可写的
从常规代码的角度来看,这完全是有意义的,但在反序列化过程中则不然
FormatterServices.GetUninitializedObject()
返回一个对象,我想我需要避免它,因为它是装箱的,因此速度要慢得多
初始化此类结构数组的最快方法是什么
更新:目前,我看到的唯一现实的方法是动态生成struct T的克隆,但字段上没有readonly属性,填写它们,在内存中修复两个数组并进行内存复制 仅仅因为反序列化并不意味着你就可以打破语言规则。如果我尝试以下操作,编译器会抱怨:
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);
}
我同意这种语言,但是表达式更接近IL生成和反射,这两种方式都允许我执行这样的操作。GetUninitializedObject()是专门为对象世界中的这些情况而设计的。@Yurik:这一点很好。然而,请注意Eric Lippert对此帖子的评论:。虽然反射技术上允许您这样做,但规范中并没有规定所有CLR实现都需要这样做。你将依赖于未指明的行为。表达式介于实际语言和编译代码之间。在这种情况下,它们的行为更像语言,而不像纯IL。Microsoft本身允许只读字段序列化,因此它是合法的。DataContractSerializer是通过IL生成来实现的,但是表达式应该提供一种可行的替代方法。但是谢谢你的详尽回答。这应该是公认的答案。因为“不可能”对任何人都没有帮助。
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);
}