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);
}