属性和命名/可选构造函数参数不起作用

时间:2011-11-18 22:13:15

标签: c# custom-attributes

我有自定义的自定义属性:

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

两个构造函数参数都是可选的。

在像这样的字段上使用此属性时

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

我在代码编辑器中没有看到任何波浪形但我看到一个模糊的错误,没有任何文件行号列。错误消息是:

  

错误CS0182:属性参数必须是常量表达式,typeof表达式   或属性参数类型

的数组创建表达式

单击该错误不会执行任何操作。也就是说,您没有被导航到错误站点(显然,因为没有行号和列)。

即使我设置了这样的属性:

[EnumDisplay("This is a Bill")] 

编译器不喜欢它。

实际上,我被迫提供两个参数(已命名或未命名),以便将此属性用作属性。

当然,如果我将此属性用作常规类,如下所示:

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");

编译器将接受上述任何一种“样式”。

当然,我遗失了一些东西,或者我的大脑不能正常工作。

3 个答案:

答案 0 :(得分:28)

在C#中已存在的属性的可选值之后,可选参数被添加到C#中。因此,对于可选的属性参数,您应该回退到特定于属性的语法:

[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,
}

如您所见,最终结果实际上是相同的,但不是使用命名参数,而是使用命名属性(其中[EnumDisplay(Description = null, Code = "C")]之类的语法只能在属性声明中使用)。

另一种思考方式是属性声明从方法/构造函数调用“借用”其语法,但属性声明本身不是 方法调用,因此它们不会完全相同作为方法的特征。

答案 1 :(得分:5)

如果您确实想使用构造函数将值推送到属性中(例如,如果某些属性的属性是必需的,或者对它们执行某种处理),您可以随时上学并重载构造函数。

例如:

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

答案 2 :(得分:3)

可选参数实际上不是可选的,方法签名中包含所有参数,属性是特殊的(存在于可选参数之前,并且当作为属性应用时具有不同的规则(例如,考虑谁调用属性构造函数))。但我想,将来会增加支持。

目前,如果您希望达到可选效果,请尝试以下操作:

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

}

并按原样申请:

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