代码之家  ›  专栏  ›  技术社区  ›  the_drow

何时为自定义属性类调用Destructor?

  •  4
  • the_drow  · 技术社区  · 15 年前

    假设我有这门课:

    [AttributeUsage(AttributeTargets.Method)] 
    public class MyAttribute : Attribute 
    { 
      public MyAttribute() 
      { 
        // Do stuff
      }
    
      ~MyAttribute()
      {
        // When is this called? When the function ends? Whenever the GC feels like?
      }
    }
    
    2 回复  |  直到 15 年前
        1
  •  2
  •   Andras Zoltan    15 年前

    在通过in Reflector调用GetCustomAttributes的示例之后,代码的托管部分(即它转换到运行时并成为外部调用的点)在CustomAttribute.GetCustomAttributes中处于关闭状态。

    [MyAttribute]
    

    将调用默认值

    [MyAttribute(1, "hello", typeof(T))]
    

    会调用一个 (Int, String, Type) .

    我看不到任何证据表明实例的缓存是执行的,这意味着属性实例在被反射时是按需创建的。

    前面提到的托管运行时转换发生在CustomAttribute.\u CreateCaObject。虽然不容易静态分析此方法是否确实缓存了它创建的实例(它可能以内存缓冲区指针的形式获得足够的状态信息,可能指示属性声明所在的元数据位置),但我们可以查看以下事实:

    • 始终调用构造函数,并且

    这告诉我属性总是构造的。

    当然,我们可以通过在测试中编写一段代码来测试这一点。

    [TestMethod]
    public void TestMethod1()
    {
      //if running in MSTest you have to allow for the test runner to reflect 
      //over the class as it looks for the TestClass attribute - therefore if our
      //assumption is correct that a new instance is always constructed when 
      //reflecting, our counter check should start at 2, not 1.
      Type t = typeof(AttributeTest);
      var attributes = 
        t.GetCustomAttributes(typeof(AttributeTest.TheAttributeAttribute), false);  
      //check counter
      Assert.AreEqual(2, AttributeTest.TheAttributeAttribute.Counter);
      var attributes2 = 
        t.GetCustomAttributes(typeof(AttributeTest.TheAttributeAttribute), false);
      //should be one louder (sorry, 'one bigger' - the Spinal Tap influence :) )
      Assert.AreEqual(3, AttributeTest.TheAttributeAttribute.Counter);
    }
    
    [TheAttribute]
    public class AttributeTest
    {
      public class TheAttributeAttribute : Attribute
      {
        static int _counter = 0;
    
        public static int Counter { get { return _counter; } }
    
        public TheAttributeAttribute()
        {
          _counter++;
          Console.WriteLine("New");
        }
      }
    }
    

    因此,元数据属性的有效使用是将它们缓存在用户代码中,当然,除非该属性在某种程度上是可变的,这使得它不适用于给定对象的所有实例 T ,或一个方法的所有“实例”(用引号括起来,因为一个方法只在内存中存储一次) m 对于类型的实例 T型 ).

    因此,在此之后,一旦代码中对它的所有引用都为空,GC就可以使用一个属性。对于该属性的所有成员也是如此。

    因此,一个使用GetCustomAttributes()检索属性、使用它然后丢弃引用的方法刚刚发布了该属性的一个新实例,以便GC在需要时进行清理。

    因此-属性实例受与所有类实例完全相同的内存管理和生存期规则的控制;因此@PieterG在他的回答中所说的是正确的——在所有对该属性的引用被释放之后,可以随时调用析构函数。

        2
  •  1
  •   Pieter Germishuys    15 年前

    当GC感觉到的时候

    Destructors (C# Programming Guide)