C# 我可以为属性使用集合初始值设定项吗?

C# 我可以为属性使用集合初始值设定项吗?,c#,attributes,custom-attributes,object-initializers,collection-initializer,C#,Attributes,Custom Attributes,Object Initializers,Collection Initializer,C#中的属性能否与集合初始值设定项一起使用 例如,我想做如下事情: [DictionaryAttribute(){{"Key", "Value"}, {"Key", "Value"}}] public class Foo { ... } 我知道属性可以有命名参数,而且由于这看起来与对象初始值设定项非常相似,我想知道集合初始值设定项是否也可用。简短的回答是否 更详细的回答:为了使类支持集合初始值设定项,它需要实现IEnumerable,并且需要有一个add方法。例如: public class

C#中的属性能否与集合初始值设定项一起使用

例如,我想做如下事情:

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

我知道属性可以有命名参数,而且由于这看起来与对象初始值设定项非常相似,我想知道集合初始值设定项是否也可用。

简短的回答是否

更详细的回答:为了使类支持集合初始值设定项,它需要实现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();
    }
}

但这并不能编译:(我不确定限制到底在哪里,我猜属性不是像普通对象那样被更新的,因此它不受支持。我想知道这在理论上是否能被该语言的未来版本所支持……

更新:很抱歉,我弄错了-自定义类型的传递数组是不可能的:(

属性类的位置参数和命名参数的类型 仅限于以下属性参数类型:

  • 以下类型之一:bool、byte、char、double、float、, int、长、短、字符串
  • 类型对象
  • 类型System.type
  • 枚举类型,前提是它具有公共可访问性和 它嵌套在其中(如果有)也具有公共可访问性(第节) 17.2)
  • 上述类型的一维数组。
  • 来源:

    您可以声明传递自定义类型的数组:

    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()
    {
    
    }
    
    C#4.0规范的第17.1.3节特别不允许在属性参数中使用多维数组,因此虽然Foo(字符串[,]条)可能允许您调用Foo(新[,]{“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有点开心,涉及面更广,但你就是这样。不管怎样,在这个疯狂的动态世界中,知道如何使用JSON初始化对象并不是一项不好的技能


  • 谢谢你的简短回答和长篇大论!这也正是我尝试过的,但当它没有编译时,我不确定它是错误的语法还是不受支持的功能。我也不知道泛型是不允许的。仅供参考,我非常喜欢你的答案,但我决定接受@vladimir77的答案,因为它有一个明确的答案这似乎是这个问题的最佳答案。@scott:没什么大不了的。我只是想指出,这不是命名参数的问题,因为这不是你想要做的。你试图使用集合初始化器语法,这是一个完全不同的东西……是的,这是真的,命名参数完全不可用但是我想我喜欢@Vladimir77的答案的原因是因为它确切地说明了
    属性
    支持什么。因为这里有
    参数
    ,所以可以省略
    新[]{…}
    的语法更好。但是,你确定这可以编译吗?我认为属性参数有限制——常量表达式、类型表达式或数组创建表达式——正如@Jason Down所提到的。@Scott:这是一个数组创建表达式。:(顺便说一句,我会删除我的答案;正如Jason指出的,这不好。)谢谢你的更新,也谢谢你指出了MSDN的参考资料!斯科特,很抱歉-我的答案失败了。我没有赢得足够的选票。请投反对票,因为这是公平的。@vladimir77-你不应该删除你的答案!有时错误的答案仍然有用…下次只需更新你的答案,这样人们就可以理解为什么它是错误的。Th谢谢你的建议!#1似乎是一个不错的解决方案。#2对于某些场景来说是一个很好的解决方案,但并不适用于所有场景。和#3…谈论过度,但感谢你跳出框框思考!有趣的是,解决方案#3最有可能经得起时间的考验,因为你想使用的任何其他属性都不经得起时间的考验他的技巧可以直接从JsonAttribute中派生出来。但如果您所追求的是非编译解决方案,我相信其他答案中的一个会更符合您的喜好。(-)没错,您的解决方案是唯一可以编译的:)我也遇到过这种情况,我最终使用了两个一维数组,一个用于键,一个用于值。这两个数组都是字符串数组,在构造函数中,我进行了检查,以确保数组的长度匹配,以防止一些基本错误。
    [IsRequired(new[]{“CountryId”},new[]{“1”})]
    [KeyVal("key1","val1"), KeyVal("key2","val2")]
    public class Foo { ... }
    
        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 { ... }