Can I use a collection initializer for an attribute?

Is it possible to use an attribute in C # with a collection initializer?

For example, I would like to do something like the following:

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

I know that attributes can have named parameters, and since this is similar to object initializers, I was wondering if collection initializers are available.

+6
source share
3 answers

Update: I am sorry, I am mistaken - it is impossible to pass an array of a user type: (

The types of positional and named parameters for the attribute class are limited to the types of attribute parameters, which are:

  • One of the following types: bool, byte, char, double, float, int, long, short, string .
  • Type object.
  • Type System.Type.
  • An Enum type, if it has public accessibility and the types in which it is nested (if any), also has public accessibility (section 17.2).
  • One-dimensional arrays of types are higher . a source

Source: fooobar.com/questions/72853 / ....

YOU CAN RECORD a custom array transfer:

 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) { // } } 

but compilation errors occur in the attribute declaration:

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

Section 17.1.3 of the C # 4.0 specification does not specifically allow multidimensional arrays inside attribute parameters, therefore, although Foo (the string [,] bar) may allow you to call Foo (new [,] {{"a", "b"}, {"key2", "val2"}}), unfortunately, it is not available for attributes.

So, keeping in mind, a few possibilities to get closer to what you want:

  • Use a one-dimensional array with variable keys and value pairs. The obvious drawback of this approach is that it does not enforce strict observance of names and values.

  • Allow your parameter to appear several times by marking the definition of your attribute with the following attribute:

     [AttributeUsage(AllowMultiple=true)] 

    So you can now define:

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

    This is a little more verbose than I'm sure you were hoping for, but it gives a clear distinction between names and values.

  • Find the JSON package and specify the initializer for your attribute. The performance degradation is not significant as it is done during code initialization. For example, using Newtonsoft.Json, you can make an attribute like this:

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

    Which will allow you to instantiate the attribute as follows:

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

    I know this little quote is happy, much more involved, but you are here. Despite this, in this crazy dynamic world, knowing how to initialize objects using JSON is not a bad ability to have in your back pocket.

+5
source

The short answer is no.

Longer answer: in order for the class to support collection initializers, it needs to implement IEnumerable, and it needs to have an add method. For example:

 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(); } } 

Then I can do this:

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

Therefore, using this, try to make it work for the attribute. (note, since the attributes do not support generics, I just hardcode them using strings for testing):

 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(); } } 

And now, to check this out:

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

and this does not compile :( I'm not sure where the restriction is exactly, I guess that attributes are not created in the same way as a regular object, and therefore this is not supported. be curious if this could theoretically be supported by a future version of the language ... .

+3
source

Source: https://habr.com/ru/post/894220/


All Articles