Atributos y parámetros de constructor nombrados / opcionales que no funcionan

Tengo atributo personalizado definido como tal:

[AttributeUsage(AttributeTargets.Field)] public class EnumDisplayAttribute : Attribute { public string Description { get; private set; } public string Code { get; private set; } public EnumDisplayAttribute(string description = null, string code = null) { Description = description; Code = code; } } 

Ambos parámetros del constructor son opcionales.

Cuando se utiliza este atributo en un campo como tal

  public enum TransactionType { [EnumDisplay(code: "B")] Bill, [EnumDisplay(description: null, code: "C")] CashReceipt, } 

No veo ningún squigglies en el editor de código, pero veo un error vago sin ningún número de línea de archivo de columna. El mensaje de error es:

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

Al hacer clic en el error no hace nada. Es decir, no se navega al sitio de error (obviamente, ya que no hay un número de línea ni una columna).

incluso si configuro el atributo de esta manera:

 [EnumDisplay("This is a Bill")] 

Al comstackdor no le gusta.

Efectivamente, me veo obligado a proporcionar ambos parámetros (nombrados o no) para usar este atributo como un atributo.

Por supuesto, si uso este atributo como una clase regular así:

 var enumDisplayAttribute = new EnumDisplayAttribute(); enumDisplayAttribute = new EnumDisplayAttribute(description: "This is a Bill"); enumDisplayAttribute = new EnumDisplayAttribute(code: "B"); enumDisplayAttribute = new EnumDisplayAttribute(description: "This is a Bill", code: "B"); enumDisplayAttribute = new EnumDisplayAttribute("This is a Bill", "B"); enumDisplayAttribute = new EnumDisplayAttribute("This is a Bill"); 

El comstackdor aceptará cualquiera de los “estilos” anteriores.

Seguramente, me estoy perdiendo algo o mi cerebro simplemente no funciona.

Los parámetros opcionales se agregaron a C # después de que los valores opcionales para los atributos ya existían en C #. Por lo tanto, para los parámetros de atributo opcionales, debería recurrir a la syntax específica del atributo:

 [AttributeUsage(AttributeTargets.Field)] public class EnumDisplayAttribute : Attribute { public string Description { get; set; } public string Code { get; set; } public EnumDisplayAttribute() { } } public enum TransactionType { [EnumDisplay(Code = "B")] Bill, [EnumDisplay(Description = null, Code = "C")] CashReceipt, } 

Como ve, el resultado final es efectivamente el mismo, pero en lugar de usar argumentos con nombre, está usando propiedades con nombre (donde la syntax como [EnumDisplay(Description = null, Code = "C")] solo es posible en las declaraciones de atributos) .

Otra forma de verlo es que las declaraciones de atributos “tomaron prestada” su syntax de invocaciones de método / constructor, pero las declaraciones de atributos no son en sí mismas invocaciones de método, por lo que no tienen las mismas características que los métodos.

Si desea insertar valores en su atributo utilizando un constructor (por ejemplo, si algunas de las propiedades de su atributo son obligatorias o para realizar algún tipo de procesamiento en ellos), siempre puede ir a la vieja escuela y sobrecargar al constructor.

Por ejemplo:

 [AttributeUsage(AttributeTargets.Field)] public class SampleAttribute : Attribute { public string MandatoryProperty { get; private set; } public string OptionalProperty { get; private set; } // we use an overload here instead of optional parameters because // C# does not currently support optional constructor parameters in attributes public SampleAttribute(string mandatoryProperty) : this(mandatoryProperty, null) { } public SampleAttribute(string mandatoryProperty, string optionalProperty) { MandatoryProperty = mandatoryProperty; OptionalProperty = optionalProperty; } } 

Los parámetros opcionales no son realmente opcionales, la firma del método tiene todos los argumentos y los atributos son especiales (existían antes de los parámetros opcionales y tienen diferentes reglas cuando se aplican como un atributo (por ejemplo, considere quién llama al constructor del atributo)). Sin embargo, me imagino que ese apoyo se añadirá en el futuro.

Por ahora, si deseas lograr el efecto opcional prueba lo siguiente:

 [AttributeUsage(AttributeTargets.Field)] public class EnumDisplayAttribute : Attribute { public string Description { get; set; } public string Code { get; set; } } 

Y aplicar como tal:

 [EnumDisplay(Description = null, Code = "C")] private object _aField;