vendredi 24 décembre 2021

Common Language Runtime detected an invalid program in DateTime getter

I'm making a class for generating wrappers in runtime, that get a class like this:

class Test
{
    public int A { get; set; }

    public int B { get; set; }

    public string C { get; set; }

    public DateTimeOffset D { get; set; }
    
    public bool E { get; set; }
}

and creates a wrapper type like

class newTest
{
    private Test _inner;

    public newTest(Test inner)
    {
        _inner = inner;
    }
    
    public int A { get => _inner.A; }

    public int B { get => _inner.B; }

    public string C
    {
        get => _inner.C;
    }

    public DateTime D
    {
        get => _inner.D.UtcDateTime;
    }
    
    public short E
    {
        get => (short)(_inner.E ? 1 : 0);
    }
}

and all works fine, except getter for property D (only the DateTime part in utc timezone is needed). Code for adding property for DateTimeOffset is

        private static void AddDateTimeOffsetProperty(TypeBuilder typeBuilder, FieldInfo fieldBuilder,
        PropertyInfo field)
    {
        var propBuilder = typeBuilder.DefineProperty(field.Name
            , PropertyAttributes.HasDefault
            , typeof(DateTime)
            , null);

        var getBuilder = typeBuilder.DefineMethod($"get_{field.Name}",
            _getAttr,
            typeof(DateTime),
            Type.EmptyTypes);

        ILGenerator ilGen = getBuilder.GetILGenerator();
        // load args to memory
        ilGen.Emit(OpCodes.Ldarg_0);
        // load required field from "_inner" obj
        ilGen.Emit(OpCodes.Ldfld, fieldBuilder);
        // call _inner getter
        ilGen.EmitCall(OpCodes.Callvirt, field.GetMethod!, Array.Empty<Type>());

        // alloc local variable
        ilGen.Emit(OpCodes.Stloc_0);
        ilGen.Emit(OpCodes.Ldloca_S);

        MethodInfo utcDateTimeMethod = typeof(DateTimeOffset).GetProperty("UtcDateTime").GetMethod;
        // get UtcDateTime
        ilGen.EmitCall(OpCodes.Call, utcDateTimeMethod!, Array.Empty<Type>());
        // return
        ilGen.Emit(OpCodes.Ret);

        propBuilder.SetGetMethod(getBuilder);
    }

Here "field" is the property of inner class. After class was generated, create instance of Test class and wrap it

                var testObj = new Test
        {
            A = 7,
            B = 6,
            C = "World",
            E = false,
            D = DateTimeOffset.UtcNow.ToOffset(TimeSpan.FromHours(7)),
            F = 14
        };

        var wrapper = Activator.CreateInstance(wrapperTypeForTest, testObj);

after that wrapper.D will return "Common Language Runtime detected an invalid program.", other properties work.





Aucun commentaire:

Enregistrer un commentaire