C#属性を配列またはその他の可変数の引数で初期化できますか?


105

可変数の引数で初期化できる属性を作成することは可能ですか?

例えば:

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

12
配列の構文が間違っているだけです。「new int [] {3,4,5}」である必要があります。
David Wengier 2008年

回答:


178

属性は配列を取ります。paramsただし、属性を制御する場合は、代わりに使用することもできます(これは、消費者にとってより良いIMO)。

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

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

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

配列を作成するための構文はたまたまずれています。

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

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

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

33

できますが、CLSに準拠していません。

[assembly: CLSCompliant(true)]

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

ショー:

Warning 1   Arrays as attribute arguments is not CLS-compliant

通常のリフレクションを使用する場合は、複数の属性を持つことをお勧めします。

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

ただし、これはTypeDescriptor/ PropertyDescriptorで機能しません。属性の単一のインスタンスのみがサポートされます(最初または最後のどちらが勝ったか、私はどちらを思い出すことができません)。


3
注:複数の属性には、属性にAttributeUsage属性が必要です。stackoverflow.com/questions/553540/...
russau

23

次のようにコンストラクタを宣言してみてください:

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

その後、次のように使用できます。

[MyCustomAttribute(3, 4, 5)]


12

それは大丈夫です。仕様のセクション17.2から:

式Eは、以下のステートメントがすべて当てはまる場合、attribute-argument-expressionです。

  • Eのタイプは属性パラメータータイプです(§17.1.3)。
  • コンパイル時に、Eの値は次のいずれかに解決できます。
    • 定数値。
    • System.Typeオブジェクト。
    • attribute-argument-expressionsの1次元配列。

次に例を示します。

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
ただし、CLSコンプライアンスには
注意し

4

はい。ただし、渡す配列を初期化する必要があります。以下は、可変数のコマンドラインオプションをテストする単体テストの行テストの例です。

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

2

出来るよ。別の例は次のとおりです。

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

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

1

Marc Gravellの答えに戻ると、はい、配列パラメーターで属性を定義できますが、配列パラメーターで属性を適用することはCLSに準拠していません。ただし、配列プロパティで属性を定義するだけで完全にCLSに準拠します。

これに気付いたのは、CLS準拠のライブラリであるJson.NETに、オブジェクトの配列であるItemConverterParametersという名前のプロパティを持つ属性クラスJsonPropertyAttributeがあることです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.