12

我正在使用反射来映射对象。这些对象在托管代码中,但除了通过反射之外,我无法看到它们的源代码、底层结构等。所有这一切的首要目标是对象的基本内存映射(在功能上类似于 SOS.dllDumpObject!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_firstCharm_stringLength是属性的支持字段,但FirstChar字符串Length的实际内容保存在字符属性中。这是一个索引属性,可以对其进行索引以返回字符串中的所有字符,但我找不到保存字符串字符的相应字段。关于为什么会这样的任何想法?或者如何获取索引属性的支持字段?

4

3 回答 3

5

属性的支持字段的名称是编译器实现的细节,并且将来总是可以更改,即使您弄清楚了模式。

我认为您已经回答了您的问题:忽略所有属性

请记住,属性只是变相的一两个函数。只有在源代码特别请求时,属性才会有编译器生成的支持字段。例如,在 C# 中:

public string Foo { get; set; }

但是类的创建者不需要像这样使用编译器生成的属性。例如,一个属性可能会获取一个常量值,多个属性可能会获取/设置位字段的不同部分,等等。在这些情况下,您不会期望看到每个属性都有一个支持字段。忽略这些属性很好。您的代码不会遗漏任何实际数据。

于 2013-01-14T16:50:47.513 回答
3

可以完全忽略所有属性。如果一个属性没有支持字段,那么它根本不会消耗任何内存。

此外,除非您愿意(尝试)解析 CIL,否则您将无法获得此类映射。考虑这段代码:

private DateTime today;

public DateTime CurrentDay
{
    get { return today; }
}

您希望如何确定today字段和CurrentDay属性之间存在某种关系?

编辑:关于您最近的问题:

如果您的属性包含类似 的代码return 2.6;,则该值不会保存在任何地方,该常量直接嵌​​入在代码中。

关于string:string由 CLR 以特殊方式处理。如果您尝试反编译它的索引器,您会注意到它是由 CLR 实现的。对于这几个特殊类型(string、数组、int...),您无法通过查看它们的字段来找到它们的大小。对于所有其他类型,您可以。

于 2013-01-14T16:50:50.613 回答
1

回答您的另一个问题:在什么情况下属性没有支持字段?

public DateTime CurrentDay
{
    get { return DateTime.Now; }
}

或属性可以使用任何其他数量的支持字段/类

public string FullName 
{
    get {return firstName + " " + lastName;}
}
于 2013-01-14T16:57:36.603 回答