使用Reflection确定哪些字段是属性的后备字段
我正在使用reflection来绘制对象。 这些对象在托管代码中,但除了通过reflection之外,我无法看到它们的源代码,底层结构等。 所有这一切的首要目标是一个对象的基本内存映射(类似于SOS.dll DumpObject
和!ObjSize
命令的function)。 因此,我试图确定哪些成员被“双重计算”为一个字段和一个属性。
例如:
public class CalendarEntry { // private property private DateTime date { get; set;} // public field public string day = "DAY"; }
映射时显示:
- 字段
- 天
- k__BackingField
- 属性
- 日期
像这样的一个类:
public class CalendarEntry { // private field private DateTime date; // public field public string day = "DAY"; // Public property exposes date field safely. public DateTime Date { get { return date; } set { date = value; } } }
映射时显示:
- 字段
- 天
- 日期
- 属性
- 日期
乍一看没有什么可以告诉你Date
属性的“支持字段”是名为date
的字段。 我试图避免在这种情况下计算两次日期,因为这会给我一个糟糕的内存大小近似值。
更令人困惑/复杂的是我遇到过这样的场景,其中属性并不总是具有将通过Type.GetFields()
方法列出的相应字段,因此我不能完全忽略所有属性。
关于如何确定从Type.GetFields()
返回的集合中的字段是否实际上是从Type.GetProperties()
返回的某些相应属性的支持字段的任何想法?
编辑 – 我无法确定属性在Type.GetFields()
返回的集合中列出的相应字段的条件。 有人熟悉这种情况吗?
编辑2-我找到了一个很好的例子,说明属性的支持字段何时不会包含在从Type.GetFields()
返回的集合中。 在String的引擎盖下查看时,您有以下内容:
- Object包含名为FirstChar的Property
- Object包含名为Chars的Property
- Object包含名为Length的Property
- 对象包含名为m_stringLength的字段
- 对象包含名为m_firstChar的字段
- 对象包含名为Empty的字段
- 对象包含名为TrimHead的字段
- 对象包含名为TrimTail的字段
- 对象包含名为TrimBoth的字段
- Object包含名为charPtrAlignConst的字段
- 对象包含名为alignConst的字段
m_firstChar
和m_stringLength
是Properties FirstChar
和Length
的支持字段,但字符串的实际内容保存在Chars属性中。 这是一个索引属性,可以索引它以返回String中的所有字符,但是我找不到包含字符串字符的相应字段。 对此为何的任何想法? 或者如何获取索引属性的支持字段?
属性的支持字段的名称是编译器实现细节,即使您找出模式,也可以在将来进行更改。
我想你已经找到了问题的答案: 忽略所有属性 。
请记住,一个属性只是一个或两个伪装的function。 在源代码特别请求时,属性将只有编译器生成的支持字段。 例如,在C#中:
public string Foo { get; set; }
但是类的创建者不需要像这样使用编译器生成的属性。 例如,属性可能获得常量值,多个属性可能获取/设置位字段的不同部分,依此类推。 在这些情况下,您不希望看到每个属性的单个支持字段。 忽略这些属性是好的。 您的代码不会遗漏任何实际数据。
您可以完全忽略所有属性。 如果属性没有支持字段,那么它根本不消耗任何内存。
此外,除非您愿意(尝试)解析CIL,否则您将无法获得此类映射。 考虑以下代码:
private DateTime today; public DateTime CurrentDay { get { return today; } }
您如何看待today
领域与CurrentDay
属性之间存在某种关系?
编辑:关于你最近的问题:
如果您的属性包含return 2.6;
等代码return 2.6;
,然后该值不保存在任何地方,该常量直接嵌入代码中。
关于string
: string
由CLR以特殊方式处理。 如果您尝试反编译其索引器,您会注意到它是由CLR实现的。 对于这些特殊类型( string
,array, int
,…),您无法通过查看其字段来查找它们的大小。 对于所有其他类型,您可以。
回答你的另一个问题:在什么情况下,物业没有支持领域?
public DateTime CurrentDay { get { return DateTime.Now; } }
或财产可以使用任何其他数量的支持领域/类
public string FullName { get {return firstName + " " + lastName;} }