c# generics .net-attributes

¿Por qué C#prohíbe los tipos de atributos genéricos?



generics .net-attributes (6)

Bueno, no puedo responder por qué no está disponible, pero puedo confirmar que no es un problema de CLI. La especificación de CLI no lo menciona (por lo que puedo ver) y si usa IL directamente, puede crear un atributo genérico. La parte de la especificación C # 3 que la prohíbe - sección 10.1.4 "Especificación de base de clase" no da ninguna justificación.

La especificación ECMA C # 2 anotada tampoco proporciona ninguna información útil, aunque sí proporciona un ejemplo de lo que no está permitido.

Mi copia de la especificación anotada de C # 3 debería llegar mañana ... Veré si eso da más información. De todos modos, es definitivamente una decisión de lenguaje en lugar de una de tiempo de ejecución.

EDITAR: Respuesta de Eric Lippert (parafraseado): no hay una razón particular, excepto para evitar la complejidad tanto en el lenguaje como en el compilador para un caso de uso que no agrega mucho valor.

Esto provoca una excepción en tiempo de compilación:

public sealed class ValidatesAttribute<T> : Attribute { } [Validates<string>] public static class StringValidation { }

Me doy cuenta de que C # no soporta atributos genéricos. Sin embargo, después de muchas búsquedas en Google, parece que no puedo encontrar la razón.

¿Alguien sabe por qué los tipos genéricos no pueden derivar de un Attribute ? ¿Alguna teoría?


Esta es una muy buena pregunta. En mi experiencia con los atributos, creo que la restricción está en su lugar porque al reflexionar sobre un atributo crearía una condición en la que tendría que verificar todas las permutaciones de tipo posibles: typeof(Validates<string>) , typeof(Validates<SomeCustomType>) , etc ...

En mi opinión, si se requiere una validación personalizada según el tipo, un atributo puede no ser el mejor enfoque.

Tal vez una mejor clase de validación que tome un SomeCustomValidationDelegate o un ISomeCustomValidator como un parámetro sería un mejor enfoque.


Esto no es realmente genérico y aún debe escribir una clase de atributo específica por tipo, pero puede utilizar una interfaz base genérica para codificar un poco a la defensiva, escribir un código menor que el requerido, obtener los beneficios del polimorfismo, 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 { }


Mi solución es algo como esto:

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


No sé por qué no está permitido, pero esta es una solución posible

[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 { .... }


Un atributo decora una clase en tiempo de compilación, pero una clase genérica no recibe su información de tipo final hasta el tiempo de ejecución. Dado que el atributo puede afectar a la compilación, debe estar "completo" en el momento de la compilación.

Consulte este artículo de MSDN para obtener más información.