74 votes

Quand le constructeur d'un attribut personnalisé est-il exécuté ?

Quand est-il exécuté ? S'exécute-t-il pour chaque objet sur lequel je l'applique, ou une seule fois ? Peut-il faire quelque chose, ou ses actions sont-elles limitées ?

66voto

Fredrik Mörk Points 85694

Quand le constructeur est-il exécuté ? Essayez-le avec un exemple :

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; }
}

Et quel est le résultat ?

Creating MyClass instance
Setting value in MyClass instance
Getting attributes for MyClass type
Running constructor

Ainsi, le constructeur d'attribut est exécuté lorsque nous commençons à examiner l'attribut. Notez que l'attribut est récupéré à partir du type, et non de l'instance du type.

15voto

romkyns Points 17295

Le constructeur est exécuté à chaque fois le site GetCustomAttributes est invoqué ou lorsqu'un autre code invoque directement le constructeur. .

Notez qu'au moins dans .NET 4.0, les instances de l'attribut sont pas en cachette ; une nouvelle instance est construite à chaque fois GetCustomAttributes s'appelle :

[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;
    }
}

Bien entendu, ce n'est pas la meilleure idée de faire en sorte que les attributs se comportent de cette manière. À tout le moins, notez que GetCustomAttributes est no n'est pas documenté pour se comporter de cette manière ; en fait, ce qui se passe dans le programme ci-dessus n'est pas spécifié dans la documentation.

6voto

Christian Klauser Points 2611

Définissez un point d'arrêt du débogueur à l'intérieur d'un constructeur d'attributs et écrivez du code de réflexion qui lit ces attributs. Vous remarquerez que les objets attributs ne seront pas créés avant d'être renvoyés par l'API de réflexion. Les attributs sont par classe . Ils font partie des métadonnées.

Jetez un coup d'oeil à ça :

Programme.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();
    }
}

MonAttribut.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; }    
}

Résultat

Program started
MyAttribute created with 15.
15
Program ended

Mais ne vous inquiétez pas des performances des constructeurs d'attributs. Ils sont la partie la plus rapide de la réflexion :-P

4voto

280Z28 Points 49515

Les métadonnées de l'exécutable ou de la DLL sont stockées :

  • A jeton de métadonnées indiquant le constructeur à appeler
  • Les arguments

Lorsque j'arriverai à cette section de mon implémentation CLI, je prévois d'appeler le constructeur paresseusement la première fois. GetCustomAttributes() est appelé pour le ICustomAttributeProvider . Si un type d'attribut particulier est demandé, je ne construirai que ceux qui sont nécessaires pour retourner ce type.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X