自定义属性的构造函数何时运行?

什么时候开始?它是为我应用它的每个对象运行,还是只运行一次?它能做任何事情吗,或者它的行动受到限制吗?

29273 次浏览

构造函数什么时候运行:

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

因此,当我们开始检查属性时,将运行属性构造函数。请注意,属性是从类型获取的,而不是从类型的实例获取的。

可执行文件或 DLL 存储中的元数据:

  • 指示要调用的构造函数的 元数据标记
  • 争吵

当我到达 CLI 实现的那一部分时,我计划在第一次为 ICustomAttributeProvider调用 GetCustomAttributes()时延迟调用构造函数。如果请求特定的属性类型,我将只构造返回该类型所需的属性类型。

在属性构造函数中设置调试器断点,并编写一些读取这些属性的反射代码。您会注意到,在从反射 API 返回属性对象之前,不会创建这些属性对象。属性是 每班。它们是元数据的一部分。

看看这个:

程序

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

构造函数运行 每次都是,调用 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没有的文档,其行为是这样的; 事实上,上述程序中发生的事情并没有在文档中指定。