Когда вызыватель вызывается для пользовательского класса атрибута? - PullRequest
4 голосов
/ 13 июля 2010

Скажите, у меня есть этот класс:

[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 ]

1 голос
/ 13 июля 2010

После примера вызова GetCustomAttributes в Reflector управляемая часть кода (т. Е. Точка, в которой он переходит в среду выполнения и становится внешним вызовом) недоступна в CustomAttribute.GetCustomAttributes.

На этом этапе метод проверяет байты метаданных, окружающих объект, для которого загружаются атрибуты.

Там есть код, который затем делает дальнейшие размышления, чтобы найти вызываемый конструктор времени выполнения. Э.Г.

[MyAttribute]

будет вызывать по умолчанию, тогда как

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

будет вызывать конструктор, который принимает (Int, String, Type).

Я не вижу никаких доказательств того, что выполняется кэширование экземпляров, что означает, что экземпляры атрибутов создаются по требованию, когда они отражаются.

Доказательство

Вышеупомянутый переход управляемой среды выполнения происходит в CustomAttribute._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 говорит в своем ответе, является правильным - деструктор может быть вызван в любое время после того, как все ссылки на этот атрибут были освобождены.

1 голос
/ 13 июля 2010

Всякий раз, когда GC чувствует, как это

Деструкторы не могут быть вызваны.Они вызываются автоматически.

Деструкторы (Руководство по программированию в C #)

...