我可以使用数组或其他可变数量的参数初始化C#属性吗?

时间:2021-03-26 23:15:35

Is it possible to create an attribute that can be initialized with a variable number of arguments?

是否可以创建一个可以使用可变数量的参数初始化的属性?

For example:

[MyCustomAttribute(new int[]{ 3, 4, 5})]  // this doesn't work
public MyClass ...

7 个解决方案

#1


153  

Attributes will take an array. Though if you control the attribute, you can also use params instead (which is nicer to consumers, IMO):

属性将采用数组。虽然如果你控制属性,你也可以使用params(这对消费者来说更好,IMO):

class MyCustomAttribute : Attribute {
    public int[] Values { get; set; }

    public MyCustomAttribute(params int[] values) {
       this.Values = values;
    }
}

[MyCustomAttribute(3, 4, 5)]
class MyClass { }

Your syntax for array creation just happens to be off:

您的数组创建语法恰好关闭:

class MyCustomAttribute : Attribute {
    public int[] Values { get; set; }

    public MyCustomAttribute(int[] values) {
        this.Values = values;
    }
}

[MyCustomAttribute(new int[] { 3, 4, 5 })]
class MyClass { }

#2


30  

You can do it, but it isn't CLS compliant:

你可以这样做,但它不符合CLS:

[assembly: CLSCompliant(true)]

class Foo : Attribute
{
    public Foo(string[] vals) { }
}
[Foo(new string[] {"abc","def"})]
static void Bar() {}

Shows:

Warning 1   Arrays as attribute arguments is not CLS-compliant

For regular reflection usage, it may be preferable to have multiple attributes, i.e.

对于常规反射使用,可能最好具有多个属性,即

[Foo("abc"), Foo("def")]

However, this won't work with TypeDescriptor/PropertyDescriptor, where only a single instance of any attribute is supported (either the first or last wins, I can't recall which).

但是,这不适用于TypeDescriptor / PropertyDescriptor,其中只支持任何属性的单个实例(第一个或最后一个获胜,我无法回想起哪个)。

#3


17  

Try declaring the constructor like this:

尝试像这样声明构造函数:

public class MyCustomAttribute : Attribute
{
    public MyCustomAttribute(params int[] t)
    {
    }
}

Then you can use it like:

然后你就可以使用它:

[MyCustomAttribute(3, 4, 5)]

[MyCustomAttribute(3,4,5)]

#4


12  

That should be okay. From the spec, section 17.2:

那应该没问题。从规范,第17.2节:

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

如果以下所有语句都为真,则表达式E是attribute-argument-expression:

  • The type of E is an attribute parameter type (§17.1.3).
  • E的类型是属性参数类型(第17.1.3节)。

  • At compile-time, the value of E can be resolved to one of the following:
    • A constant value.
    • 一个恒定的值。

    • A System.Type object.
    • System.Type对象。

    • A one-dimensional array of attribute-argument-expressions.
    • 属性参数表达式的一维数组。

  • 在编译时,E的值可以解析为以下之一:常量值。 System.Type对象。属性参数表达式的一维数组。

Here's an example:

这是一个例子:

using System;

[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public class SampleAttribute : Attribute
{
    public SampleAttribute(int[] foo)
    {
    }
}

[Sample(new int[]{1, 3, 5})]
class Test
{
}

#5


4  

Yes, but you need to initialize the array that you are passing in. Here is an example from a row test in our unit tests that tests a variable number of command line options;

是的,但您需要初始化您传入的数组。以下是我们的单元测试中的行测试示例,该测试用于测试可变数量的命令行选项;

[Row( new[] { "-l", "/port:13102", "-lfsw" } )]
public void MyTest( string[] args ) { //... }

#6


1  

You can do that. Another example could be:

你可以做到这一点。另一个例子可能是:

class MyAttribute: Attribute
{
    public MyAttribute(params object[] args)
    {
    }
}

[MyAttribute("hello", 2, 3.14f)]
class Program
{
    static void Main(string[] args)
    {
    }
}

#7


1  

To piggy back on Marc Gravell's answer, yes you can define an attribute with array parameters but applying an attribute with an array parameter is not CLS-compliant. However just defining an attribute with an array property is perfectly CLS-compliant.

为了回顾Marc Gravell的答案,是的,您可以使用数组参数定义属性,但应用具有数组参数的属性不符合CLS。但是,仅使用数组属性定义属性完全符合CLS。

What made me realize this was that Json.NET, a CLS-compliant library, has an attribute class JsonPropertyAttribute with a property named ItemConverterParameters that's an array of objects.

让我意识到这一点的是,Json.NET是一个符合CLS的库,它有一个属性类JsonPropertyAttribute,它有一个名为ItemConverterParameters的属性,它是一个对象数组。

#1


153  

Attributes will take an array. Though if you control the attribute, you can also use params instead (which is nicer to consumers, IMO):

属性将采用数组。虽然如果你控制属性,你也可以使用params(这对消费者来说更好,IMO):

class MyCustomAttribute : Attribute {
    public int[] Values { get; set; }

    public MyCustomAttribute(params int[] values) {
       this.Values = values;
    }
}

[MyCustomAttribute(3, 4, 5)]
class MyClass { }

Your syntax for array creation just happens to be off:

您的数组创建语法恰好关闭:

class MyCustomAttribute : Attribute {
    public int[] Values { get; set; }

    public MyCustomAttribute(int[] values) {
        this.Values = values;
    }
}

[MyCustomAttribute(new int[] { 3, 4, 5 })]
class MyClass { }

#2


30  

You can do it, but it isn't CLS compliant:

你可以这样做,但它不符合CLS:

[assembly: CLSCompliant(true)]

class Foo : Attribute
{
    public Foo(string[] vals) { }
}
[Foo(new string[] {"abc","def"})]
static void Bar() {}

Shows:

Warning 1   Arrays as attribute arguments is not CLS-compliant

For regular reflection usage, it may be preferable to have multiple attributes, i.e.

对于常规反射使用,可能最好具有多个属性,即

[Foo("abc"), Foo("def")]

However, this won't work with TypeDescriptor/PropertyDescriptor, where only a single instance of any attribute is supported (either the first or last wins, I can't recall which).

但是,这不适用于TypeDescriptor / PropertyDescriptor,其中只支持任何属性的单个实例(第一个或最后一个获胜,我无法回想起哪个)。

#3


17  

Try declaring the constructor like this:

尝试像这样声明构造函数:

public class MyCustomAttribute : Attribute
{
    public MyCustomAttribute(params int[] t)
    {
    }
}

Then you can use it like:

然后你就可以使用它:

[MyCustomAttribute(3, 4, 5)]

[MyCustomAttribute(3,4,5)]

#4


12  

That should be okay. From the spec, section 17.2:

那应该没问题。从规范,第17.2节:

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

如果以下所有语句都为真,则表达式E是attribute-argument-expression:

  • The type of E is an attribute parameter type (§17.1.3).
  • E的类型是属性参数类型(第17.1.3节)。

  • At compile-time, the value of E can be resolved to one of the following:
    • A constant value.
    • 一个恒定的值。

    • A System.Type object.
    • System.Type对象。

    • A one-dimensional array of attribute-argument-expressions.
    • 属性参数表达式的一维数组。

  • 在编译时,E的值可以解析为以下之一:常量值。 System.Type对象。属性参数表达式的一维数组。

Here's an example:

这是一个例子:

using System;

[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public class SampleAttribute : Attribute
{
    public SampleAttribute(int[] foo)
    {
    }
}

[Sample(new int[]{1, 3, 5})]
class Test
{
}

#5


4  

Yes, but you need to initialize the array that you are passing in. Here is an example from a row test in our unit tests that tests a variable number of command line options;

是的,但您需要初始化您传入的数组。以下是我们的单元测试中的行测试示例,该测试用于测试可变数量的命令行选项;

[Row( new[] { "-l", "/port:13102", "-lfsw" } )]
public void MyTest( string[] args ) { //... }

#6


1  

You can do that. Another example could be:

你可以做到这一点。另一个例子可能是:

class MyAttribute: Attribute
{
    public MyAttribute(params object[] args)
    {
    }
}

[MyAttribute("hello", 2, 3.14f)]
class Program
{
    static void Main(string[] args)
    {
    }
}

#7


1  

To piggy back on Marc Gravell's answer, yes you can define an attribute with array parameters but applying an attribute with an array parameter is not CLS-compliant. However just defining an attribute with an array property is perfectly CLS-compliant.

为了回顾Marc Gravell的答案,是的,您可以使用数组参数定义属性,但应用具有数组参数的属性不符合CLS。但是,仅使用数组属性定义属性完全符合CLS。

What made me realize this was that Json.NET, a CLS-compliant library, has an attribute class JsonPropertyAttribute with a property named ItemConverterParameters that's an array of objects.

让我意识到这一点的是,Json.NET是一个符合CLS的库,它有一个属性类JsonPropertyAttribute,它有一个名为ItemConverterParameters的属性,它是一个对象数组。