我使用反射来映射对象。这些对象在托管代码中,但除了通过反射之外,我无法看到它们的源代码、底层结构等。所有这一切的首要目标是一个对象的基本内存映射(在功能上类似于SOS.dll DumpObject
和!ObjSize
命令)。因此,我试图确定哪些成员被"重复计算"为字段和属性。
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的底层时,可以看到以下内容:
- 对象包含名为FirstChar的属性
- 对象包含名为Chars的属性
- 对象包含名为Length的属性
- 对象包含名为m_stringLength的字段
- 对象包含名为m_firstChar的字段
- 对象包含名为Empty的字段
- 对象包含名为TrimHead的字段
- 对象包含名为TrimTail的字段
- 对象包含名为TrimBoth的字段
- 对象包含名为charPtrAlignConst的字段
- 对象包含名为alignConst的字段
m_firstChar
和m_stringLength
是属性FirstChar
和Length
的后台字段,但字符串的实际内容保存在Chars属性中。这是一个索引属性,可以被索引以返回字符串中的所有字符,但我找不到一个对应的字段,其中包含字符串的字符。有什么想法吗?或者如何获得索引属性的后置字段?
属性的支持字段的名称是编译器的实现细节,即使您找到了模式,也可以在将来更改。
我想你已经找到了问题的答案:忽略所有属性。
请记住,属性只是伪装的一两个函数。只有当源代码特别请求时,属性才会有编译器生成的支持字段。例如,在c#中:
public string Foo { get; set; }
但是类的创建者不需要像这样使用编译器生成的属性。例如,一个属性可能得到一个常量,多个属性可能得到/设置位字段的不同部分,等等。在这些情况下,您不会期望看到每个属性都有一个支持字段。忽略这些属性是可以的。您的代码不会遗漏任何实际数据。
您可以完全忽略所有属性。如果一个属性没有后备字段,那么它根本不消耗任何内存。
此外,除非您愿意(尝试)解析CIL,否则您将无法获得这样的映射。考虑以下代码:
private DateTime today;
public DateTime CurrentDay
{
get { return today; }
}
你希望如何找出today
字段和CurrentDay
属性之间存在某种关系?
EDIT:关于你最近的问题:
如果你的属性包含像return 2.6;
这样的代码,那么该值不会被保存在任何地方,该常量直接嵌入到代码中。
关于string
: string
由CLR以一种特殊的方式处理。如果您尝试反编译它的索引器,您会注意到它是由CLR实现的。对于这几个特殊类型(string
, array, int
,…),您不能通过查看它们的字段来找到它们的大小。对于所有其他类型,可以。
回答您的另一个问题:在什么情况下属性没有支持字段?
public DateTime CurrentDay
{
get { return DateTime.Now; }
}
或属性可以使用任何其他数量的支持字段/类
public string FullName
{
get {return firstName + " " + lastName;}
}