C#中的属性可以与集合初始值设定项一起使用吗?
例如,我想做类似以下的事情:
[DictionaryAttribute(){{"Key", "Value"}, {"Key", "Value"}}]
public class Foo { ... }
我知道属性可以有命名参数,因为这看起来与对象初始化器非常相似,我想知道集合初始化器是否也可用。
答案 0 :(得分:6)
更新:我很抱歉我错了 - 传递自定义类型的数组是不可能的:(
属性类的位置和命名参数的类型 仅限于属性参数类型,它们是:
- 以下类型之一: bool,byte,char,double,float, int,long,short,string 。
- 类型对象。
- 类型System.Type。
- Enum类型,前提是它具有公共可访问性和类型 嵌套的(如果有的话)也具有公共可访问性(Section 17.2)。
- 以上类型的一维数组。 source
醇>
来源: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()
{
}
答案 1 :(得分:5)
C#4.0规范的第17.1.3节特别不允许在属性参数内部使用多维数组,所以虽然Foo(string [,] bar)可能允许你调用Foo(new [,] {{“a” ,“b”},{“key2”,“val2”}}),遗憾的是,它不适用于属性。
因此,考虑到这一点,有几种可能性来近似你想要的东西:
使用具有交替键和值对的一维数组。这种方法的明显缺点是它并没有完全强制执行名称和值。
通过使用以下属性标记属性定义,允许您的参数多次出现:
[AttributeUsage(AllowMultiple=true)]
通过这种方式,您现在可以定义:
[KeyVal("key1","val1"), KeyVal("key2","val2")]
public class Foo { ... }
这比我确定你所希望的有点晦涩,但它在名称和价值观之间做了明确的界定。
查找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初始化对象并不是一个糟糕的技能。
答案 2 :(得分: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
{
}
并且没有编译:(我不确定限制的确切位置,我猜测属性不像常规对象那样新建,因此不支持。我会如果理论上可以通过该语言的未来版本支持,那就很好奇....