How to initialize structure in array with readonly values ​​using expression trees in C #

I need to generate code using expression trees that quickly populates an array of structures T[]

where T contains a readonly field. I need to initialize it like after GetUninitializedObject () + IL or reflection based settings.

UPDATE: It seems impossible at the moment. Please vote for it in MS proposals

struct Strct
{
    public readonly int Value;
}

      

this code doesn't work:

Expression.Assign(
    Expression.Field(structByIndexFromArrayExp, "Value"),
    deserializedValueExp)

      

While building the expression tree, I get this error: Expression must be writeable

Which makes perfect sense from a normal code point of view, but not during deserialization.

FormatterServices.GetUninitializedObject()

returns an object, which I think I need to avoid as it is boxed and therefore significantly slower.

What's the fastest way to initialize such structured arrays?

Update: At the moment, the only real way I can see is to dynamically generate a clone of the structure T, but without the readonly attribute on the fields, fill them, fix both the arrays in memory, and do memory copying. Please vote to let Microsoft know about it .

+3


source to share


2 answers


Just because you are deserializing does not mean that you are breaking the rules of the language. The compiler complains if I try this:

void Main()
{
    var a = new Foo{Bar = 1};
}

public struct Foo
{
    public readonly int Bar;
}

      

Expression trees cannot be expected to perform actions that cannot be performed in code. If the property shouldn't be readonly

, remove the keyword readonly

. Otherwise, you should have a constructor that allows you to initialize it.



public struct Foo
{
    public Foo(int bar) {this.Bar = bar;}
    public readonly int Bar;
}

      

Then create an expression that calls that constructor, rather than trying to set the field directly.

+6


source


This is actually a workaround as you can use expressions to call reflection methods. Keep in mind that this is much slower.



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

      

+1


source







All Articles