2011-12-05 20 views
25

¿Hay alguna manera de forzar al compilador a restringir el uso de un atributo personalizado para ser utilizado solo en tipos específicos de tipos int, short, string (todos los tipos primitivos)?
similar a AttributeUsageAttribute 's ValidOn- AttributeTargets enumeración.Permitir un atributo personalizado solo en el tipo específico

+0

No, esto no es posible. Lo máximo que puede hacer es escribir una prueba unitaria que use la reflexión y valide su uso. Pero nada en el compilador hará esto. – Amy

+0

también; no puede agregar atributos a clases fuera de su control * de todos modos * - por lo que no puede agregar atributos a 'int' o' string'. ¿Quiere decir "solo para propiedades que * son *' int' o 'cadena'"? si es así, la respuesta sigue siendo "no"; p –

+0

@MarcGravell por supuesto, menciono int, propiedades de cadena y no cambio la clase int en sí misma, pero editaré. gracias por la respuesta. – gdoron

Respuesta

21

No, no puedes, básicamente. Puede limitarlo a struct frente a class frente a interface, eso es todo. Además: no puede agregar atributos a tipos fuera de su código de todos modos (a excepción de a través de TypeDescriptor, que no es lo mismo).

4

Puede escribir el código usted mismo para imponer el uso correcto de su clase de atributo, pero eso es todo lo que puede hacer.

+5

nota al margen: un atributo no tiene acceso a su propio contexto, por lo que cualquier comprobación aquí tendría que estar en el código de reflexión que consulta el atributo –

+1

Escribí una prueba unitaria (NUnit) una vez que usé Cecil para verificar mis usos de atributo "permisible". – Amy

+0

Buenos tiempos ..... –

4

Puede ejecutar esta prueba de unidad para verificarlo.

En primer lugar, declarar la validación de atributos PropertyType:

[AttributeUsage(AttributeTargets.Class)] 
    // [JetBrains.Annotations.BaseTypeRequired(typeof(Attribute))] uncomment if you use JetBrains.Annotations 
    public class PropertyTypeAttribute : Attribute 
    { 
     public Type[] Types { get; private set; } 

     public PropertyTypeAttribute(params Type[] types) 
     { 
      Types = types; 
     } 
    } 

Crear prueba de unidad:

[TestClass] 
    public class TestPropertyType 
    { 
     public static Type GetNullableUnderlying(Type nullableType) 
     { 
      return Nullable.GetUnderlyingType(nullableType) ?? nullableType; 
     } 

     [TestMethod] 
     public void Test_PropertyType() 
     { 
      var allTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()); 
      var allPropertyInfos = allTypes.SelectMany(a => a.GetProperties()).ToArray(); 

      foreach (var propertyInfo in allPropertyInfos) 
      { 
       var propertyType = GetNullableUnderlying(propertyInfo.PropertyType); 
       foreach (var attribute in propertyInfo.GetCustomAttributes(true)) 
       { 
        var attributes = attribute.GetType().GetCustomAttributes(true).OfType<PropertyTypeAttribute>(); 
        foreach (var propertyTypeAttr in attributes) 
         if (!propertyTypeAttr.Types.Contains(propertyType)) 
          throw new Exception(string.Format(
           "Property '{0}.{1}' has invalid type: '{2}'. Allowed types for attribute '{3}': {4}", 
           propertyInfo.DeclaringType, 
           propertyInfo.Name, 
           propertyInfo.PropertyType, 
           attribute.GetType(), 
           string.Join(",", propertyTypeAttr.Types.Select(x => "'" + x.ToString() + "'")))); 
       } 
      } 
     } 
    } 

Su atributo, por ejemplo, permitir que los tipos de propiedad única decimales:

[AttributeUsage(AttributeTargets.Property)] 
    [PropertyType(typeof(decimal))] 
    public class PriceAttribute : Attribute 
    { 

    } 

Ejemplo modelo:

public class TestModel 
{ 
    [Price] 
    public decimal Price1 { get; set; } // ok 

    [Price] 
    public double Price2 { get; set; } // error 
} 
Cuestiones relacionadas