7

C#の属性をコレクション初期化子で使用できますか?

たとえば、次のようなことをしたいと思います。

[DictionaryAttribute(){{"Key", "Value"}, {"Key", "Value"}}]
public class Foo { ... }

属性に名前付きパラメーターを含めることができることは知っていますが、それはオブジェクト初期化子と非常に似ているように見えるので、コレクション初期化子も使用できるかどうか疑問に思いました。

4

3 に答える 3

6

更新:申し訳ありませんが、間違っています-カスタムタイプの配列を渡すことは不可能です:(

属性クラスの位置パラメーターと名前付きパラメーターのタイプは、属性パラメーターのタイプに制限されています。

  1. 次のいずれかのタイプ:bool、byte、char、double、float、int、long、short、string
  2. タイプオブジェクト。
  3. タイプSystem.Type。
  4. 列挙型は、パブリックアクセシビリティがあり、ネストされているタイプ(存在する場合)にもパブリックアクセシビリティがあります(セクション17.2)。
  5. 上記のタイプ の1次元配列。ソース

ソース:stackoverflow

カスタムタイプの配列を渡すことを宣言できます。

class TestType
{
  public int Id { get; set; }
  public string Value { get; set; }

  public TestType(int id, string value)
  {
    Id = id;
    Value = value;
  }
}

class TestAttribute : Attribute
{
  public TestAttribute(params TestType[] array)
  {
    //
  }
}

ただし、属性宣言でコンパイルエラーが発生します。

[Test(new[]{new TestType(1, "1"), new TestType(2, "2"), })]
public void Test()
{

}
于 2011-08-03T20:27:42.590 に答える
6

C#4.0仕様のセクション17.1.3では、属性パラメーター内の多次元配列は特に許可されていないため、Foo(string [、] bar)ではFoo(new [、] {{"a"、 "b "}、{" key2 "、" val2 "}})、残念ながら、属性には使用できません。

したがって、それを念頭に置いて、必要なものを概算するためのいくつかの可能性は次のとおりです。

  1. キーと値のペアが交互になっている1次元配列を使用します。このアプローチの明らかな欠点は、名前と値を正確に適用していないことです。

  2. 次の属性で属性定義にタグを付けることにより、パラメーターが複数回表示されるようにします。

    [AttributeUsage(AllowMultiple=true)]
    

    このようにして、次のことを定義できます。

    [KeyVal("key1","val1"), KeyVal("key2","val2")]
    public class Foo { ... }
    

    これは、あなたが望んでいたと私が確信しているものよりも少し言葉遣いですが、名前と値の間の明確な描写をします。

  3. JSONパッケージを見つけて、属性の初期化子を提供します。これはコードの初期化中に行われるため、パフォーマンスへの影響は重要ではありません。たとえば、Newtonsoft.Jsonを使用すると、次のような属性を作成できます。

        public class JsonAttribute : Attribute
        {
          Dictionary<string, string> _nameValues = 
              new Dictionary<string, string>();
          public JsonAttribute(string jsoninit)
          {
            var dictionary = new Dictionary<string, string>();
            dynamic obj = JsonConvert.DeserializeObject(jsoninit);
            foreach(var item in obj)
              _nameValues[item.Name] = item.Value.Value;
          }
        }
    

    これにより、次のような属性をインスタンス化できます。

    [Json(@"{""key1"":""val1"", ""key2"":""val2""}")]
    public class Foo { ... }
    

    私はそれが少し引用であることを知っています-幸せで、もっと複雑ですが、あなたはそこにいます。とにかく、このクレイジーでダイナミックな世界では、JSONを使用してオブジェクトを初期化する方法を知っていることは、後ポケットに入れるのに悪いスキルではありません。

于 2011-08-03T21:26:00.840 に答える
3

簡単な答えはノーです。

より長い答え:クラスがコレクション初期化子をサポートするためには、IEnumerableを実装する必要があり、addメソッドが必要です。したがって、たとえば:

public class MyClass<T,U> : IEnumerable<T>
{
    public void Add(T t, U u)
    {
    }

    public IEnumerator<T> GetEnumerator()
    {
        throw new NotImplementedException();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

その後、これを行うことができます:

var mc = new MyClass<int, string> {{1, ""}, {2, ""}};

それで、これを使用して、属性に対して機能するようにしてみましょう。(補足として、属性はジェネリックスをサポートしていないため、テスト用の文字列を使用してハードコーディングしているだけです):

public class CollectionInitAttribute : Attribute, IEnumerable<string>
{
    public void Add(string s1, string s2)
    {

    }

    public IEnumerator<string> GetEnumerator()
    {
        throw new NotImplementedException();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

そして今それをテストするために:

[CollectionInit{{"1","1"}}]
public class MyClass
{

}

そしてそれはコンパイルされません:(制限が正確にどこにあるのかわかりません、私は属性が通常のオブジェクトと同じように更新されていないので、これはサポートされていないと思います。これは理論的には、言語の将来のバージョンでサポートされる可能性があります。

于 2011-08-03T20:26:10.440 に答える