命名参数类型约束

时间:2011-04-27 19:53:17

标签: c# .net-3.5 custom-attributes

我正在设计一个自定义属性类。

public class MyAttr: Attribute
{
    public ValueRange ValRange { get; set; }
}

然后我尝试将此属性分配给相邻类中的属性:

public class Foo
{
    [MyAttr(ValRange= new ValueRange())]
    public string Prop { get; set; }
}  

然而,编译器抱怨以下内容:

  

'ValRange'不是有效的命名属性参数,因为它不是有效的属性参数类型

我还尝试将ValueRange类转换为struct,希望成为值类型可以解决问题。有没有办法解决这个问题?

5 个答案:

答案 0 :(得分:21)

  

有什么方法吗?

没有

有关详细信息,请参阅C#4规范的第17.1.3节,为方便起见,我在此重现:


  

属性类的位置和命名参数的类型仅限于属性参数类型,它们是:

     
      
  • 以下类型之一:bool,byte,char,double,float,int,long,sbyte,short,string,uint,ulong,ushort。
  •   
  • 类型对象。
  •   
  • 类型System.Type。
  •   
  • 枚举类型,前提是它具有公共可访问性,并且嵌套类型(如果有)也具有公共可访问性。
  •   
  • 上述类型的一维数组。
  •   
     

没有这些类型之一的构造函数参数或公共字段不能用作属性规范中的位置参数或命名参数。


请记住,属性的要点是在编译时将信息添加到与您放置属性的实体关联的元数据。这意味着与该属性相关的所有信息必须具有明确定义的,明确的方式来将其序列化为元数据。通过将合法类型集限制为所有可能类型的一小部分,我们确保编译器始终可以发出消费者可以理解的合法元数据。

答案 1 :(得分:2)

属性参数值需要在编译时解析(即常量)。

请参阅MSDN上的Attribute Parameter Types

  

传递给属性的值必须在编译时为编译器所知。

如果您可以创建一个常量ValueRange,则可以使用它。

答案 2 :(得分:1)

属性参数必须是值of the following types(引用文章):

  • 简单类型(bool,byte,char,short,int,long,float和double)
  • 字符串
  • 的System.Type
  • 枚举
  • object(对象类型的属性参数的参数必须是上述类型之一的常量值。)
  • 任何上述类型的一维阵列

编辑:将“编译时常量”更改为“值”,因为类型和数组不是常量(感谢指出这一点的评论者(并且由于某种原因随后删除了他的评论......)

答案 3 :(得分:1)

属性只能接收编译时常量作为参数(例如3,“hello”,typeof(MyClass),“定义所需非常数据的资源的路径”)。

我给出的最后一个示例(传递类型)可以帮助您设计一种解决方法(通过您需要的方法传递实现接口的类型)。

答案 4 :(得分:1)

  

有什么方法吗?

您可以让您的属性使用Type属性,然后使用实现已定义的接口的类型,处理该属性的代码必须假设 em>,并且因此也创建隐式,但希望记录,对其客户的要求:

public interface IValueRange {
  int Start { get; }
  int End { get; }
}
public class MyAttr : Attribute { 
  // The used type must implement IValueRange
  public Type ValueRangeType { get; set; } 
}

// ....

public class Foo { 

  class FooValueRange : IValueRange {
    public int Start { get { return 10; } }
    public int End { get { return 20; } }
  }
  [MyAttr(ValueRangeType = typeof(FooValueRange))]
  public string Prop { get; set; }

}

这与System.ComponentModel命名空间中的许多类没有什么不同,例如DesignerAttribute