如何在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的克隆,但字段上没有只读属性,填充它们,修复内存中的两个数组,并进行内存复制。请投票告诉微软修复它。

如何在C#中使用表达式树用只读值初始化数组中的结构

反序列化并不意味着违反了语言规则。如果我尝试这个,编译器会抱怨:

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