我正在尝试编写一些.NET代码,这些代码从仅包含属性setter / getters的简单接口列表中动态生成各种类型。我想从列表中生成的类型之一是支持给定接口(具有自动生成的支持字段),但也跟踪所有属性集操作,记录哪些属性已更改(以及将来可能的时间,进行更改的上下文,用户等)。在C#中构建样本并使用ILDASM对其进行检查后,我已经使用了它,但是有一部分代码对IL来说似乎比它应该复杂得多。对于这种类型,在定义属性的setter的代码中,我将值设置为字段(足够简单),但是我需要为我设置的属性获取PropertyInfo
(所以稍后用户可以枚举已更改的属性的PropertyInfo
s。为了获得我在定义中间的setter的属性的PropertyInfo
,我有以下代码(中间部分):
...
PropertyBuilder pb = tb.DefineProperty(property.Name, property.Attributes, property.PropertyType, null);
MethodAttributes attr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
MethodBuilder setmb = tb.DefineMethod(SetPropertyMethodPrefix + property.Name, attr, null, new Type[] { property.PropertyType });
ILGenerator setgen = setmb.GetILGenerator();
...
// store the value in the backing field
setgen.Emit(OpCodes.Ldarg_0);
setgen.Emit(OpCodes.Ldarg_1);
setgen.Emit(OpCodes.Stfld, fb);
// get ready to give the change tracker the PropertyInfo for this property
setgen.Emit(OpCodes.Ldarg_0);
setgen.Emit(OpCodes.Ldfld, changeTrackerField);
// get the PropertyInfo for this property (there has to be a better way!)
setgen.Emit(OpCodes.Ldarg_0);
setgen.Emit(OpCodes.Call, typeof(object).GetMethod("GetType"));
// alternatively, instead of the two lines above, I can get the type token directly and get the type from there, which may or may not be any faster...
// setgen.Emit(OpCodes.Ldtoken, tb.TypeToken.Token);
// setgen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }));
setgen.Emit(OpCodes.Ldstr, property.Name);
setgen.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("GetProperty", new Type[] { typeof(string) }));
// give the PropertyInfo to our change tracking object
setgen.Emit(OpCodes.Callvirt, typeof(ChangeTracker).GetMethod("MarkPropertyChanged"));
setgen.Emit(OpCodes.Ret);
中间部分相当于C#代码:GetType().GetProperty(<propertyName>)
,但似乎应该有一些更快的方法来获取我正在构建中的属性的PropertyInfo
。 GetTypeFromHandle
版似乎可能更有效(typeof(T)与this.GetType()),但我猜有一种方法可以完全绕过GetProperty
,也许使用{{ 1}}。
有没有办法获取我正在构建中的属性的PropertyBuilder.PropertyToken
实例,而不需要插入可以自我反射的IL代码?
答案 0 :(得分:0)
我理解有人会认为有一些方法可以通过方法体中的令牌来引用属性(或事件),但这是不可能的。唯一可行的操作码是ldtoken
,但只接受方法,字段或类型。我看到了你的顾虑,但我建议先做一些基准测试,看看调用 GetProperty 是否真的是代码的性能瓶颈。但是,您还有其他几个选项可以引用该属性。
遍历所有属性并检查其令牌(在CIL中以整数形式发出)。
使用字典作为从属性令牌到实际 PropertyInfo 的映射。在构造函数中填充字典,或者懒洋洋地填充。
记住构建属性的顺序,并使用它来索引GetProperties
返回的数组。我想订单应该是相同的,但最好检查一下。
答案 1 :(得分:0)
为了解决过去类似的问题,我创建了一个静态可访问的Dictionary,其中long是一个简单的,原子递增的唯一ID。然后,您可以使用静态方法调用检索PropertyInfo或任何其他对象,并将您创建的令牌硬编码到动态方法中。