55 votes

Comment puis-classes d'attributs travail?

Mes recherches de continuer de tourner jusqu'seuls guides expliquant comment utiliser et appliquer les attributs d'une classe. Je veux apprendre à créer mes propres classes d'attributs et de la mécanique de la façon dont ils travaillent.

Comment sont les classes d'attributs instancié? Ils sont instanciés lorsque la classe, elles sont appliquées à l'est instancié? Est un instancié pour chaque classe instanciée qu'il est appliqué? E. g. si je demande à la classe SerializableAttribute à un MyData classe, et j'instancie 5 MyData cas, il y aura 5 instances de la SerializbleAttribute classe créée en coulisses? Ou est-il simplement une instance partagée entre tous?

Comment faire attribut des instances de classe accéder à la classe à laquelle ils sont associés? Comment une classe SerializableAttribute accéder à la classe à laquelle il est appliqué de sorte qu'il peut sérialiser des données? A-t-elle une sorte de SerializableAttribute.ThisIsTheInstanceIAmAppliedTo propriété? :) Ou est-ce de travailler dans le sens inverse que chaque fois que je sérialiser quelque chose, la fonction Serialize je passe l'instance de Maclasse à la volonté de reflectively passer par les Attributs et trouver la SerialiableAttribute exemple?

36voto

Artiom Chilaru Points 5049

Je n'ai pas utiliser les attributs dans ma journée-à-jour de travail avant, mais j'ai lu à leur sujet. Aussi, j'ai fait quelques tests, pour sauvegarder ce que je vais dire ici. Si je me trompe, en tout lieu, - n'hésitez pas à me dire cela :)

De ce que je sais, les attributs ne sont pas en agissant comme des classes régulières. Ils ne sont pas instanciés lorsque vous créez un objet auxquels ils s'appliquent, et non pas une instance statique, pas de 1 pour chaque instance de l'objet. Ni à accéder à la classe à laquelle ils sont appliqués..

Au lieu de cela, ils agissent comme des propriétés (attributs? :P ) de la classe. Pas comme le .NET classe de propriétés, plus comme dans le "une propriété de verre est la transparence" de ce genre de propriété. Vous pouvez vérifier quels sont les attributs appliqués à une classe de la réflexion, et ensuite agir en conséquence. Ils sont essentiellement des méta-données attachées à la définition de la classe, et non pas les objets de ce type.

Vous pouvez essayer d'obtenir la liste des attributs d'une classe, une méthode, une propriété, etc etc.. Quand vous obtenez la liste de ces attributs - c'est là où ils seront instanciés. Ensuite, vous pouvez agir sur les données à l'intérieur de ces attributs.

E. g. le Linq tables, les propriétés ont des attributs qui définissent qui table/colonne, ils se réfèrent. Mais ces classes ne pas utiliser ces attributs. Au lieu de cela, le DataContext va vérifier les attributs de ces objets lorsqu'il vous permet de convertir expression linq arbres de code SQL.

Maintenant, pour certains d'exemples réels.. j'ai couru dans ces LinqPad, donc ne vous inquiétez pas à propos de l'étrange méthode Dump (). Je l'ai remplacé par de la Console.WriteLine pour rendre le code plus facile à comprendre pour les gens qui ne la connaissent pas :)

void Main()
{
    Console.WriteLine("before class constructor");
    var test = new TestClass();
    Console.WriteLine("after class constructor");

    var attrs = Attribute.GetCustomAttributes(test.GetType()).Dump();
    foreach(var attr in attrs)
        if (attr is TestClassAttribute)
            Console.WriteLine(attr.ToString());
}

public class TestClassAttribute : Attribute
{
    public TestClassAttribute()
    {
        DefaultDescription = "hello";
        Console.WriteLine("I am here. I'm the attribute constructor!");
    }
    public String CustomDescription {get;set;}
    public String DefaultDescription{get;set;}

    public override String ToString()
    {
        return String.Format("Custom: {0}; Default: {1}", CustomDescription, DefaultDescription);
    }
}

[Serializable]
[TestClass(CustomDescription="custm")]
public class TestClass
{
    public int Foo {get;set;}
}

La console résultat de cette méthode est:

before class constructor
after class constructor
I am here. I'm the attribute constructor!
Custom: custm; Default: hello

Et l' Attribute.GetCustomAttributes(test.GetType()) retourne ce tableau: (le tableau affiche toutes les colonnes disponibles pour toutes les entrées.. Donc non, l'attribut Serializable n'ont pas ces propriétés :) ) LinqPad Attributes Array

Avez d'autres questions? N'hésitez pas à demander!

UPD: J'ai vu que vous poser une question: pourquoi les utiliser? Un exemple, je vais vous parler de la XML-RPC.NET de la bibliothèque. Vous créez votre XML-RPC classe de service, avec des méthodes qui représentera le xml-rpc méthodes. La chose principale est maintenant de: en XmlRpc les noms de méthode peuvent avoir certains caractères spéciaux, comme des points. Donc, vous pouvez avoir un flexlabs.ProcessTask() xml rpc méthode.

Vous définissez cette classe comme suit:

[XmlRpcMethod("flexlabs.ProcessTask")]
public int ProcessTask_MyCustomName_BecauseILikeIt();

Cela me permet de m'nom de la méthode dans la façon dont je l'aime, tout en continuant d'utiliser le nom public comme il se doit.

16voto

Chris Taylor Points 25865

Les attributs sont essentiellement des méta-données qui peuvent être attachés aux différentes pièces de votre code. Ce méta-données peuvent ensuite être interogate et d'influer sur le comportement de certains opperations.

Attributs peut être appliqué à presque tous les aspects de votre code. Par exemple, les attributs peuvent être associés au niveau de l'Assemblage, comme le AssemblyVersion et AssemblyFileVersion des attributs, qui régissent les numéros de version des associés à l'assemblée.

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Alors l'attribut Serializable, par exemple, peut être appliqué à une déclaration de type pour signaler le type de soutien de la sérialisation. En fait, cet attribut a une signification spéciale dans le CLR et est stockée comme une directive spéciale directement sur le type dans l'IL, c'est optimisée pour être stocké comme un indicateur de bit qui peuvent être traitées beaucoup plus efficacement, il ya quelques attributs de cette nature, qui sont connus comme pseudo attributs personnalisés.

Encore d'autres attributs peuvent être appliqués à des méthodes, propriétés, domaines, les énumérations, les valeurs de retour etc. Vous pouvez vous faire une idée des cibles possibles d'un attribut peut être appliqué à par regarder ce lien http://msdn.microsoft.com/en-us/library/system.attributetargets(SV.90).aspx

En outre, vous pouvez définir vos propres attributs personnalisés qui peuvent ensuite être appliquées aux cibles que vos attributs sont destinés. Puis au moment de l'exécution de votre code pourrait réfléchir sur les valeurs contenues dans les attributs personnalisés et de prendre les mesures appropriées.

Pour un peu candide exemple, et c'est juste pour l'exemple :) Vous pourriez écrire une persistance moteur de mapper automatiquement les Classes de tables dans votre base de données et de cartographier les propriétés de la Classe à des colonnes de table. Vous pourriez commencer par la définition des deux attributs personnalisés

TableMappingAttribute
ColumnMappingAttribute

Vous pouvez ensuite les appliquer à vos classes, à titre d'exemple, nous avons une Personne de la classe

[TableMapping("People")]
public class Person
{
  [ColumnMapping("fname")]
  public string FirstName {get; set;}

  [ColumnMapping("lname")]
  public string LastName {get; set;}
}

Lors de cette compile, autre que le fait que le compilateur émet supplémentaires méta-données définies par les attributs personnalisés, peu de choses sont touchés. Cependant, vous pouvez maintenant écrire un PersistanceManager qui peut dynamiquement inspecter les attributs d'une instance de la classe Personne et insérer les données dans le les Gens la table, la cartographie des données dans le nom de la propriété de la fname colonne et le Nom de la propriété à la colonne lname.

Quant à votre question concernant le cas des attributs de l'instance de l'attribut n'est pas créé pour chaque instance de votre Classe. Toutes les instances de Gens vont partager la même instance de la TableMappingAttribute et ColumnMappingAttributes. En fait, l'attribut instances sont créées uniquement lorsque vous en fait la requête pour les attributs de la première fois.

6voto

Aren Points 17843

Oui ils sont instanciés avec les paramètres que vous lui attribuez.

L'attribut n'est pas "accès" de la classe. L'attribut est attaché à la classe' / propriété de la liste d'attributs dans la réflexion de données.

[Serializable]
public class MyFancyClass
{ ... }

// Somewhere Else:

public void function()
{
   Type t = typeof(MyFancyClass);
   var attributes = t.GetCustomAttributes(true);

   if (attributes.Count(p => p is SerializableAttribute) > 0)
   {
       // This class is serializable, let's do something with it!

   }     
}

6voto

Gishu Points 59012

Pensez attributs sont des post-its qui sont attachés à la les classes ou les définitions de méthode (intégré dans l'assemblée des métadonnées).

Vous pouvez ensuite avoir un processeur/runner/module inspecteur qui accepte ces types en réfléchissant, semble pour ces post-its et les traite différemment. Cela s'appelle la programmation déclarative. Vous déclarez certains comportements plutôt que d'écrire du code pour eux dans le type.

  • Serializable attribut sur un type déclare qu'il est construit pour être sérialisé. Le XmlSerializer peut alors accepter un objet de cette classe et de faire le nécessaire. Vous marquez les méthodes qui doivent être sérialisé/caché avec le droit des post-its.
  • un autre exemple serait la NUnit. Le NUnit coureur regarde le [TestFixture] les attributs de toutes les classes définies dans la cible de l'assemblée pour identifier les classes de test. Il recherche ensuite les méthodes marqué avec [Test] attribut pour identifier les tests, qu'il s'exécute et affiche les résultats.

Vous pouvez courir à travers ce tutoriel sur le site MSDN qui a le plus de réponses à vos questions avec un exemple à la fin. Bien qu'ils pourraient avoir extrait une méthode appelée Audit(Type anyType); au lieu de dupliquer le code. L'exemple 'affiche de l'information" par l'inspection des attributs.. mais vous pourriez faire quelque chose dans la même veine.

2voto

Will Marcouiller Points 11649

Si vous jetez un œil sur cette téléchargeable à code source ouvert LINQ to Active Directory (CodePlex), vous pourriez trouver intéressant le mécanisme des Attributs.cs fichier où Bart De Smet a écrit tous ses attributs de définitions de classes. J'ai appris attributs il.

En bref, vous pouvez vous spécialiser les Attribut de la classe et le code spécialisée propriétés pour vos besoins.

public class MyOwnAttributeClass : Attribute {
    public MyOwnAttributeClass() {
    }
    public MyOwnAttributeClass(string myName) {
        MyName = myName;
    }
    public string MyName { get; set; }
}

et puis, vous pouvez l'utiliser partout où MyOwnAttributeClass devient utile. Il pourrait soit être plus de la définition d'une classe ou d'une définition de propriété.

[MyOwnAttributeClass("MyCustomerName")]
public class Customer {
    [MyOwnAttributeClass("MyCustomerNameProperty")]
    public string CustomerName { get; set; }
}

Ensuite, vous pouvez l'obtenir par le biais de la réflexion de la sorte:

Attribute[] attributes = typeof(Customer).GetCustomAttribute(typeof(MyOwnAttributeClass));

Considérer que l'attribut que vous mettez entre crochets est toujours le constructeur de votre attribut. Donc, si vous voulez avoir un paramétrée attribut, vous avez besoin de votre code constructeur en tant que tel.

Ce code est fourni en l'état, et ne peut pas compiler. Son but est de vous donner une idée de comment cela fonctionne.

En effet, en général, vous voulez avoir un autre attribut de classe pour une classe que pour un bien.

Espérons que cette aide!

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