Когда запускается конструктор пользовательского атрибута?
Когда он запускается? Он запускается для каждого объекта, к которому я его применяю, или только один раз? Может ли он что-нибудь сделать, или его действия ограничены?
4 ответа
Когда запускается конструктор? Попробуйте это с примером:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Creating MyClass instance");
MyClass mc = new MyClass();
Console.WriteLine("Setting value in MyClass instance");
mc.Value = 1;
Console.WriteLine("Getting attributes for MyClass type");
object[] attributes = typeof(MyClass).GetCustomAttributes(true);
}
}
[AttributeUsage(AttributeTargets.All)]
public class MyAttribute : Attribute
{
public MyAttribute()
{
Console.WriteLine("Running constructor");
}
}
[MyAttribute]
class MyClass
{
public int Value { get; set; }
}
И что на выходе?
Creating MyClass instance
Setting value in MyClass instance
Getting attributes for MyClass type
Running constructor
Итак, конструктор атрибута запускается, когда мы начинаем проверять атрибут. Обратите внимание, что атрибут выбирается из типа, а не из экземпляра типа.
Конструктор запускается каждый раз, когда GetCustomAttributes
вызывается, или всякий раз, когда какой-либо другой код вызывает конструктор напрямую (не то, что есть веская причина для этого, но это также не невозможно).
Обратите внимание, что по крайней мере в.NET 4.0 экземпляры атрибутов не кэшируются; каждый раз создается новый экземпляр GetCustomAttributes
называется:
[Test]
class Program
{
public static int SomeValue;
[Test]
public static void Main(string[] args)
{
var method = typeof(Program).GetMethod("Main");
var type = typeof(Program);
SomeValue = 1;
Console.WriteLine(method.GetCustomAttributes(false)
.OfType<TestAttribute>().First().SomeValue);
// prints "1"
SomeValue = 2;
Console.WriteLine(method.GetCustomAttributes(false)
.OfType<TestAttribute>().First().SomeValue);
// prints "2"
SomeValue = 3;
Console.WriteLine(type.GetCustomAttributes(false)
.OfType<TestAttribute>().First().SomeValue);
// prints "3"
SomeValue = 4;
Console.WriteLine(type.GetCustomAttributes(false)
.OfType<TestAttribute>().First().SomeValue);
// prints "4"
Console.ReadLine();
}
}
[AttributeUsage(AttributeTargets.All)]
class TestAttribute : Attribute
{
public int SomeValue { get; private set; }
public TestAttribute()
{
SomeValue = Program.SomeValue;
}
}
Конечно, не самая лучшая идея, чтобы атрибуты вели себя так. По крайней мере, обратите внимание, что GetCustomAttributes
не зарегистрировано, чтобы вести себя как это; на самом деле, то, что происходит в вышеуказанной программе, не указано в документации.
Установите точку останова отладчика внутри конструктора атрибутов и напишите некоторый код отражения, который читает эти атрибуты. Вы заметите, что объекты атрибутов не будут созданы до тех пор, пока они не будут возвращены из API обновления. Атрибуты на класс. Они являются частью метаданных.
Посмотри на это:
Program.cs
using System;
using System.Linq;
[My(15)]
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Program started");
var ats =
from a in typeof(Program).GetCustomAttributes(typeof(MyAttribute), true)
let a2 = a as MyAttribute
where a2 != null
select a2;
foreach(var a in ats)
Console.WriteLine(a.Value);
Console.WriteLine("Program ended");
Console.ReadLine();
}
}
MyAttribute.cs
using System;
[AttributeUsage(validOn : AttributeTargets.Class)]
public class MyAttribute : Attribute
{
public MyAttribute(int x)
{
Console.WriteLine("MyAttribute created with {0}.", x);
Value = x;
}
public int Value { get; private set; }
}
Результат
Program started
MyAttribute created with 15.
15
Program ended
Но не беспокойтесь о производительности конструкторов атрибутов. Они являются самой быстрой частью отражения:-P
Метаданные в исполняемом файле или DLL хранят:
- Маркер метаданных, указывающий на конструктор для вызова
- Аргументы
Когда я доберусь до этого раздела моей реализации CLI, я планирую лениво вызвать конструктор в первый раз GetCustomAttributes()
призван для ICustomAttributeProvider
, Если запрашивается конкретный тип атрибута, я создам только те, которые требуются для возврата этого типа.