2009-08-05 18 views
54

que estoy tratando de pasar objetos en un constructor de atributos de la siguiente manera:Cómo pasar objetos en una constructora atributo

[PropertyValidation(new NullOrEmptyValidatorScheme())] 
public string Name { get; private set; } 

Con este constructor de atributos:

public PropertyValidationAttribute(IValidatorScheme validator) { 
     this._ValidatorScheme = validator; 
    } 

El código no se compilará. ¿Cómo puedo pasar un objeto a un atributo como el anterior?

EDITAR: Sí NullOrEmptyValidatorScheme implementa IValidatorScheme.

El error: error CS0182: Un argumento de atributo debe ser una expresión constante, un tipo de expresión o una expresión de creación de matriz de un tipo de parámetro de atributo.

+0

¿Cuál es el error de compilación? ¿Estás seguro de que 'NullOrEmptyValidatorScheme' implementa' IValidatorScheme'? –

+0

Como sintaxis de atributo se trata, este es código válido, por lo que debe ser algo sobre sus objetos. –

+2

@ kek444 - no, no es ... Estoy agregando la sección de especificaciones a mi respuesta ... –

Respuesta

65

Los valores en atributos están limitados a tipos simples; por ejemplo, constantes básicas (incluyendo cadenas) y typeof ... no puede usar new u otro código más complejo. En breve; no puedes hacer esto Se le puede dar la tipo sin embargo:

[PropertyValidation(typeof(NullOrEmptyValidatorScheme)] 

es decir, el PropertyValidation ctor toma un Type, y utilizar Activator.CreateInstance dentro del código para crear el objeto. Tenga en cuenta que idealmente solo debe almacenar la cadena internamente (AssemblyQualifiedName).

De ECMA 334v4:

§24.1.3 Attribute parameter types

The types of positional and named parameters for an attribute class are limited to the attribute parameter types, which are:

  • One of the following types: bool , byte , char , double , float , int , long , short , string .
  • The type object .
  • The type System.Type .
  • An enum type, provided it has public accessibility and the types in which it is nested (if any) also have public accessibility.
  • Single-dimensional arrays of the above types.

y

§24.2 Attribute specification

...

An expression E is an attribute-argument-expression if all of the following statements are true:

  • The type of E is an attribute parameter type (§24.1.3).
  • At compile-time, the value of E can be resolved to one of the following:
    • A constant value.
    • A typeof-expression (§14.5.11) specifying a non-generic type, a closed constructed type (§25.5.2), or an unbound generic type (§25.5).
    • A one-dimensional array of attribute-argument-expressions.
+0

Esta es la segunda referencia a uno de los valores permitidos que es una enumeración, sin embargo, implementarlo no ha sido trivial. ¿Conoces algún ejemplo de implementación usando enum? – QueueHammer

+0

@QueueHammer '[DefaultValue (AnyEnum.SomeValue)]' debería ser suficiente; de lo contrario, algo como '[System.Xml.Serialization.XmlElement (Form = System.Xml.Schema.XmlSchemaForm.Qualified)] ' –

10

Como críticos anteriores señalaron, los tipos utilizan en los argumentos de atributos están restringidos bastante severa (como es comprensible, ya que sus valores deben ser serializado directamente en el conjunto metadata blob).

Dicho esto, es probable que pueda crear una solución que utiliza typeofs, como los puede usarse.

Por ejemplo:

[PropertyValidation(typeof(NullOrEmptyValidatorScheme))] 
public string Name { get; private set; } 

Esta sintaxis es perfectamente legal. El código que lee sus atributos tiene que obtener el tipo de validador, crear una nueva instancia del validador (incluso puede mantener un caché de validadores codificados en los tipos de valicadores, si corresponde, esta es una técnica bastante común), y luego invocarlo .

+0

Gracias por su respuesta. He dado a Marc la respuesta aceptada. Pero su sugerencia de usar un caché es útil, y había previsto hacer esto para guardar desde muchas llamadas Activator.CreateInstance. – theringostarrs

5

también ... (creo que es un error de Microsoft)

No se puede poner un valor por defecto de "nulo", pero el valor por defecto por defecto están bien sencilla ('falso', '7', ' "Prueba").

ejemplo A continuación se le da el siguiente error: Un argumento atributo debe ser una expresión constante, typeof expresión o la creación de la matriz expresión de un tipo de parámetro atributo
en el expediente: ... \ CSC

public class SampleAttribute : Attribute 
{ 
    private string _test; 
    public SampleAttribute(string test = null) 
    { 
     _test = test; 
    } 
} 

[Sample] 
public class Toto 
{ 

} 
+0

Podría estar relacionado: "Atributos y parámetros del constructor Nombre/Opcional no funcionan" http://stackoverflow.com/q/8189807/276648 – user276648

+0

Para el usuario276648, creo que tiene razón, están relacionados y la solución parece ser más completa . Gracias ! –

+0

En realidad, con su muestra podría estar relacionado con un error del compilador (lo que significa que lo que escribió puede funcionar cuando compilado por Mono) http://stackoverflow.com/q/8290853 – user276648

Cuestiones relacionadas