【问题标题】:Initializing an Array of Structs in C#在 C# 中初始化结构数组
【发布时间】:2010-09-23 11:53:57
【问题描述】:

如何尽可能清晰地初始化 const / static 结构数组?

class SomeClass
{

    struct MyStruct
    {
        public string label;
        public int id;
    };

    const MyStruct[] MyArray = {
          {"a", 1}
          {"b", 5}
          {"q", 29}
    };
};

【问题讨论】:

    标签: c# arrays struct


    【解决方案1】:

    首先,你真的必须有一个可变结构吗?他们几乎总是一个坏主意。公共领域也是如此。有一些非常偶然的情况下它们是合理的(通常两个部分一起,如ValueTuple),但根据我的经验,它们非常罕见。

    除此之外,我只是创建一个构造函数来获取这两位数据:

    class SomeClass
    {
    
        struct MyStruct
        {
            private readonly string label;
            private readonly int id;
    
            public MyStruct (string label, int id)
            {
                this.label = label;
                this.id = id;
            }
    
            public string Label { get { return label; } }
            public string Id { get { return id; } }
    
        }
    
        static readonly IList<MyStruct> MyArray = new ReadOnlyCollection<MyStruct>
            (new[] {
                 new MyStruct ("a", 1),
                 new MyStruct ("b", 5),
                 new MyStruct ("q", 29)
            });
    }
    

    注意使用ReadOnlyCollection 而不是暴露数组本身——这将使它不可变,避免the problem exposing arrays directly。 (代码显示确实初始化了一个结构数组 - 然后它只是将引用传递给 ReadOnlyCollection&lt;&gt; 的构造函数。)

    【讨论】:

    • @Chris:不,我想说它远远超出了公开消费的 API。你的团队有多大?你总是要为那家公司工作吗?你有多确定你团队的每个成员,现在和永远,理解可变结构的许多不同的奇怪之处?对于一次性代码,我同意......但大多数代码在维护模式下的寿命比我们最初预期的要长得多,而且糟糕的设计会使以后更难解开它。您发现有人通过引用传递了一个字段,然后您无法在不破坏它的情况下重构属性,等等。
    • 很遗憾这里有这么多额外的输入。在 C++11 中,我可以这样做:struct foo { int i; const char* str; char c; }; foo f[] = { { 1, "hello", 'c' }, { 2, "goodbye", 'd'" }}; 如果不需要编写构造函数或不必输入太多“new foo”,那就太好了。
    • @Jon Skeet:我有一个问题。考虑到 label 和 id 是只读的,是否有任何理由只允许通过属性访问它们而不是让它们公开?编译器是否对其进行了优化,或者通过访问器访问它们具有将它们作为公共字段访问的开销方面?
    • @FifaEarthCup2014:这将使属性在类型中是可写的——幸运的是,这将在 C# 6 中得到修复。目前,没有办法编写一个真正只读自动实现的属性。
    • @Tutankhamen:再一次,“我已经向 OP 展示了如何创建和初始化一个数组”——你认为代码:new[] { new MyStruct ("a", 1), new MyStruct ("b", 5), new MyStruct ("q", 29) } 会做什么?它初始化一个数组。
    【解决方案2】:

    您使用的是 C# 3.0 吗?你可以像这样使用对象初始化器:

    static MyStruct[] myArray = 
                new MyStruct[]{
                    new MyStruct() { id = 1, label = "1" },
                    new MyStruct() { id = 2, label = "2" },
                    new MyStruct() { id = 3, label = "3" }
                };
    

    【讨论】:

    • 使用 C# 3,您不需要为每个构造函数调用 () (因为您正在使用对象初始化程序),并且您可以放弃“new MyStruct[]”位,因为无论如何这都是隐含的成为数组变量的初始化器。
    • 要明确,尽管出现并且缺少“新”,但它仍然会在堆上分配一个数组,而不是在堆栈上。
    【解决方案3】:

    默认情况下,您不能初始化 null 以外的引用类型。您必须将它们设为只读。所以这可以工作;

        readonly MyStruct[] MyArray = new MyStruct[]{
          new MyStruct{ label = "a", id = 1},
          new MyStruct{ label = "b", id = 5},
          new MyStruct{ label = "c", id = 1}
        };
    

    【讨论】:

    • 请注意,这只会使变量成为只读 - 它不会阻止其他代码替换数组中的元素。
    • 这个解决方案对我有用。遗憾的是,我们没有像旧的 C 风格的数组/结构初始化器那样密集和高效的东西。
    【解决方案4】:

    const 更改为static readonly 并像这样初始化它

    static readonly MyStruct[] MyArray = new[] {
        new MyStruct { label = "a", id = 1 },
        new MyStruct { label = "b", id = 5 },
        new MyStruct { label = "q", id = 29 }
    };
    

    【讨论】:

      【解决方案5】:

      我会在类上使用静态构造函数来设置静态只读数组的值。

      public class SomeClass
      {
         public readonly MyStruct[] myArray;
      
         public static SomeClass()
         {
            myArray = { {"foo", "bar"},
                        {"boo", "far"}};
         }
      }
      

      【讨论】:

      • 静态构造函数不允许访问修饰符
      猜你喜欢
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 2011-05-09
      • 1970-01-01
      相关资源
      最近更新 更多