我注意到我在MSIL中编写的一些代码以高速获取对象的任意属性并没有获得正确的DateTime属性值。无论DateTime对象的实际值如何,它总是返回相同的值。年份总是返回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; }
}
答案 0 :(得分:3)
对值类型的调用必须将托管指针作为this
参数传递。这是为了支持值类型的变异方法。
您正在将对象引用传递给值类型的盒装实例。可能,DateTime.Year
的jitted代码正在访问一些随机的内存位。你破坏了记忆安全。此IL不可验证。我不会重新计算盒装和未装箱的内存布局,但您可能正在阅读方法表或vtable的一部分或对象标题的其他部分。
使用Unbox获取指向盒装实例内容的托管指针。