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