2010-07-13 1 views

ответ

1

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

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

Существует код, который затем делает дальнейшее отражение, чтобы найти вызываемый конструктор выполнения. Например.

[MyAttribute] 

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

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

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

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

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

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

+0

Теперь, если мне нужно, чтобы класс атрибута был инстанцирован при вызове функции? –

+0

@the_drow - это можно сделать (посмотрите MethodBase.GetCurrentMethod), но вы не можете сделать это вручную в начале метода. Вы также можете взглянуть на запись суррогата выполнения, который использует выражения (поэтому, которые затем могут отражать метод, который будет вызываться, вытащить атрибут, а затем сделать все, что ему нужно), который затем может выполняться против экземпляра атрибута до выполнения этого метода что вы хотите призвать. Это отдельный вопрос SO, хотя :) –

+0

Есть ли какой-нибудь пример того, как написать такой суррогат выполнения? –

1

Всякий раз, когда GC ощущению как это

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

Destructors (C# Programming Guide)

+0

И что делать, если я использую распоряжаться? –

+0

@the_drow: dispose не влияет - это просто механизм, введенный интерфейсом и не имеющий ничего общего с собственным управлением памятью .Net –

+1

True для деструкторов (финализаторы), но это не относится к специальному случаю атрибутов –

Смежные вопросы