Question

Ceci provoque une exception lors de la compilation:

public sealed class ValidatesAttribute<T> : Attribute
{

}

[Validates<string>]
public static class StringValidation
{

}

Je réalise que C # ne supporte pas les attributs génériques. Cependant, après beaucoup de recherches sur Google, je n'arrive pas à trouver la raison.

Quelqu'un sait-il pourquoi les types génériques ne peuvent pas dériver de Attribute? Des théories?

Était-ce utile?

La solution

Eh bien, je ne peux pas dire pourquoi ce n'est pas disponible, mais je peux confirmer que ce n'est pas un problème lié à l'interface de ligne de commande. La spécification CLI ne le mentionne pas (autant que je puisse voir) et si vous utilisez directement IL, vous pouvez créer un attribut générique. La partie de la spécification C # 3 qui l'interdit - section 10.1.4 & Quot; Spécification de base de classe & Quot; ne donne aucune justification.

La spécification annotée ECMA C # 2 ne fournit aucune information utile non plus, bien qu'elle fournisse un exemple de ce qui n'est pas autorisé.

Ma copie de la spéc annotation C # 3 devrait arriver demain ... Je verrai si cela donne plus d’informations. Quoi qu’il en soit, c’est définitivement une décision linguistique plutôt que d’exécution.

EDIT: Réponse de Eric Lippert (paraphrasé): aucune raison particulière, sauf pour éviter la complexité du langage et du compilateur pour un cas d'utilisation qui n'ajoute pas beaucoup de valeur.

Autres conseils

Un attribut décore une classe au moment de la compilation, mais une classe générique ne reçoit ses informations de type final qu'au moment de l'exécution. Comme l'attribut peut affecter la compilation, il doit être & "Complet &"; au moment de la compilation.

Consultez cet article MSDN pour plus d'informations.

Je ne sais pas pourquoi ce n'est pas autorisé, mais il s'agit d'une solution de contournement possible

[AttributeUsage(AttributeTargets.Class)]
public class ClassDescriptionAttribute : Attribute
{
    public ClassDescriptionAttribute(Type KeyDataType)
    {
        _KeyDataType = KeyDataType;
    }

    public Type KeyDataType
    {
        get { return _KeyDataType; }
    }
    private Type _KeyDataType;
}


[ClassDescriptionAttribute(typeof(string))]
class Program
{
    ....
}

Ce n’est pas vraiment générique et vous devez toujours écrire une classe d’attributs spécifique par type, mais vous pourrez peut-être utiliser une interface de base générique pour coder un peu de manière défensive, écrire du code moins important que nécessaire, tirer parti du polymorphisme, etc.

//an interface which means it can't have its own implementation. 
//You might need to use extension methods on this interface for that.
public interface ValidatesAttribute<T>
{
    T Value { get; } //or whatever that is
    bool IsValid { get; } //etc
}

public class ValidatesStringAttribute : Attribute, ValidatesAttribute<string>
{
    //...
}
public class ValidatesIntAttribute : Attribute, ValidatesAttribute<int>
{
    //...
}

[ValidatesString]
public static class StringValidation
{

}
[ValidatesInt]
public static class IntValidation
{

}

C'est une très bonne question. D'après mon expérience avec les attributs, je pense que la contrainte est en place, car lors de la réflexion sur un attribut, cela créerait une condition dans laquelle vous auriez à vérifier toutes les permutations de type possibles: typeof(Validates<string>), typeof(Validates<SomeCustomType>), etc ...

À mon avis, si une validation personnalisée est requise en fonction du type, un attribut peut ne pas être la meilleure approche.

Peut-être qu'une meilleure classe de validation prenant un SomeCustomValidationDelegate ou un ISomeCustomValidator comme paramètre serait une meilleure approche.

Ma solution de contournement ressemble à ceci:

public class DistinctType1IdValidation : ValidationAttribute
{
    private readonly DistinctValidator<Type1> validator;

    public DistinctIdValidation()
    {
        validator = new DistinctValidator<Type1>(x=>x.Id);
    }

    public override bool IsValid(object value)
    {
        return validator.IsValid(value);
    }
}

public class DistinctType2NameValidation : ValidationAttribute
{
    private readonly DistinctValidator<Type2> validator;

    public DistinctType2NameValidation()
    {
        validator = new DistinctValidator<Type2>(x=>x.Name);
    }

    public override bool IsValid(object value)
    {
        return validator.IsValid(value);
    }
}

...
[DataMember, DistinctType1IdValidation ]
public Type1[] Items { get; set; }

[DataMember, DistinctType2NameValidation ]
public Type2[] Items { get; set; }

Ceci n'est pas actuellement une fonctionnalité du langage C #, cependant, il y a beaucoup de discussions sur le langage C # officiel. repo .

De quelques notes de réunion :

  

Même si cela fonctionnerait en principe, il y a des bugs dans la plupart des   versions du runtime pour qu’il ne fonctionne pas correctement (c’était   jamais exercé).

     

Nous avons besoin d'un mécanisme pour comprendre le moteur d'exécution cible sur lequel il fonctionne. nous   besoin de cela pour beaucoup de choses, et sont en train de regarder cela. Jusqu'à ce que   alors, nous ne pouvons pas le prendre.

     

Candidat pour une version majeure de C #, si nous pouvons en faire un nombre suffisant   des versions d'exécution traitent avec elle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top