C# DateTime对象未从MSIL返回正确的值

C# DateTime对象未从MSIL返回正确的值,c#,cil,il,C#,Cil,Il,我注意到,我在MSIL中编写的一些用于高速获取对象任意属性的代码没有获取正确的DateTime属性值。不管DateTime对象的实际值是多少,它总是返回相同的值,例如Year总是返回1,毫秒返回88,等等 LINQPad中的一些精简代码演示了这一点。获取mc.Inner.Age返回正确的值,mc.Inner.DateOfBirth返回正确的DateTime值,但尝试获取mc.Inner.DateOfBirth的任何特定部分总是返回错误的值。我已经研究并尝试了一些方法来让它发挥作用,但我没有足够的

我注意到,我在MSIL中编写的一些用于高速获取对象任意属性的代码没有获取正确的DateTime属性值。不管DateTime对象的实际值是多少,它总是返回相同的值,例如Year总是返回1,毫秒返回88,等等

LINQPad中的一些精简代码演示了这一点。获取mc.Inner.Age返回正确的值,mc.Inner.DateOfBirth返回正确的DateTime值,但尝试获取mc.Inner.DateOfBirth的任何特定部分总是返回错误的值。我已经研究并尝试了一些方法来让它发挥作用,但我没有足够的经验来真正知道在这一点上还有什么可以尝试的。我不确定我的代码中是否有细微的错误,或者DateTime对象是否有特殊之处导致了这种情况的发生

void Main()
{
    var mc = new MyClass();
    mc.FirstName = "Jane";
    mc.LastName = "Doe";
    mc.Inner.DateOfBirth = new DateTime(1960, 2, 13);
    mc.Inner.Age = 54;

    Object obj = mc;    
    obj = this.GetObjectProperty(obj, "Inner");
    obj = this.GetObjectProperty(obj, "DateOfBirth");
    obj = this.GetObjectProperty(obj, "Year");
    obj.Dump();

    obj = mc;
    obj = obj.GetType().GetProperty("Inner").GetValue(obj);
    obj = obj.GetType().GetProperty("DateOfBirth").GetValue(obj);
    obj = obj.GetType().GetProperty("Year").GetValue(obj);
    obj.Dump();
}

private Object GetObjectProperty(Object obj, String property)
{
    var m = obj.GetType().GetMethod("get_" + property, BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty);

    DynamicMethod meth = new DynamicMethod("GetObjectProperty", typeof(Object), new [] { typeof(Object) }, obj.GetType());
    var il = meth.GetILGenerator();

    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Castclass, obj.GetType());
    il.EmitCall(OpCodes.Call, m, null);

    if (m.ReturnType.IsValueType)
        il.Emit(OpCodes.Box, m.ReturnType);

    il.Emit(OpCodes.Ret);

    return ((GetObjectPropertyDelegate)meth.CreateDelegate(typeof(GetObjectPropertyDelegate), obj))();
}

private delegate Object GetObjectPropertyDelegate();

public class MyClass
{
    public MyClass()
    {
        this.Inner = new MyInnerClass();
    }

    public String FirstName { get; set; }
    public String LastName { get; set; }
    public MyInnerClass Inner { get; set; }
}

public class MyInnerClass
{
    public DateTime DateOfBirth { get; set; }
    public int Age { get; set; }
}

对值类型的调用必须传递一个托管指针作为
参数。这是为了支持值类型上的变异方法

您正在向值类型的装箱实例传递对象引用。可能,
DateTime.Year
的jitted代码正在访问一些随机内存位。你破坏了记忆安全。此IL不可验证。我不会重新调用已装箱和未装箱的内存布局,但您可能正在读取(部分)方法表或vtable或对象头的其他部分


用于获取指向已装箱实例内容的托管指针。

您需要注意方法中的较大缺陷。为检索到的每个属性创建一个动态方法。这使得代码的速度大大降低。只有当您可以重用动态方法时,才能更快地创建它们。您是对的。当我发现我的bug时,我从我的项目中拿出这段代码作为例子给其他人。我肯定会将代理缓存在真实案例中。谢谢你指出这一点,非常有帮助!