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

本文关键字:构造函数 参数 不起作用 属性 | 更新日期: 2023-09-27 18:15:13

我已经定义了自定义属性:

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

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

肯定是我漏了什么,或者是我的脑子坏了。

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

在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")]这样的语法只可能在属性声明中)。

另一种思考方式是,属性声明从方法/构造函数调用中"借用"了它的语法,但属性声明本身并不是方法调用中的,因此它们不能获得与方法相同的所有特性。

如果你确实想使用构造函数将值推入属性(例如,如果你的属性的某些属性是强制性的,或者对它们执行某种处理),你可以使用老式方法重载构造函数。

例如:

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

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

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

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

和apply as so:

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