【问题标题】:C#, how to handle constant tablesC#,如何处理常量表
【发布时间】:2009-09-03 23:55:38
【问题描述】:

该语言显然不包含合适的功能,这似乎很奇怪。

我发现自己的数据最好表示为多维数组,但它是完全不变的,如果不更改相关代码,任何人都无法更改它。面对 Delphi 中的这些东西,答案是显而易见的——一个以表格为值的常量。但是,C# 似乎不支持这样的东西。

Google 显示很多人对此感到不满,没有好的答案。

人们如何处理这种情况?

(不要说常量不属于代码——我遇到的最后一个是 4 个项目的所有可能排列。除非时空的本质发生变化,否则这是一成不变的。)

怎么了??有一个非常接近的答案,我正在询问一个细节,它消失了!简单地声明一个数组就可以了——唯一的问题是数组分配每次都会运行。我面前的那个包含 96 个值——我如何让它只初始化一次?我是否只需要接受比应有的范围更广的范围? (就目前而言,它在一个 3 行的例程中,相当于一个 O(n^3) 例程。)

【问题讨论】:

    标签: c# constants


    【解决方案1】:

    【讨论】:

      【解决方案2】:

      C# FAQ 中有一个关于这个特定事情的页面。

      他们建议使用静态只读数组:

      static readonly int[,] constIntArray = new int[,] { { 1, 2, 3 }, { 4, 5, 6 }};
      

      但是,请注意,这只是一种常量 - 您仍然可以重新分配数组中的各个元素。此外,由于它是静态的,因此必须在类级别上指定它,但它会很好地工作。

      【讨论】:

      • 如何让编译器接受这个?
      • Loren:我将答案编辑为多维+更明确。它完全按照类型工作,但您必须在类/结构级别指定它,而不是在方法中。
      【解决方案3】:

      您可以使用只读哈希表。唯一的缺点是 readonly 不会阻止您更改 Hashtable 中特定项目的值。所以它不是真正的 const。

      readonly Hashtable table = new Hashtable(){{1,"One"},{2,"Two"}};
      

      或者一个数组

      public readonly string[,] arry = new string[,]{{"1","2"},{"2","4"}};
      

      是的,您需要在适当的范围内声明变量,这样它就不会被多次初始化。

      【讨论】:

        【解决方案4】:

        就像他们说的那样,只需添加另一层间接。 C# 不需要提供专门的数据结构作为语言原语,尽管有时确实希望有一种方法可以使任何类不可变,但这是另一个讨论。

        现在您没有提到是否需要在其中存储不同的东西。实际上,除了多维之外,您没有提到任何其他内容,并且无法更改值或数组。我什至不知道访问模式(单个 int、int、int 索引器)是否合适。

        但一般来说,对于 3 维锯齿状数组,以下工作(但它并不漂亮)。

        需要注意的是,您构造它的类型也需要是不可变的,但这是您的问题。您可以创建自己的只读包装器。

        public static readonly ReadOnlyThreeDimensions<int> MyGlobalThree 
            = new ReadOnlyThreeDimensions<int>(IntInitializer);
        
        public class ReadOnlyThreeDimensions<T> 
        {
            private T[][][] _arrayOfT;
        
            public ReadOnlyThreeDimensions(Func<T[][][]> initializer)
            {
                _arrayOfT = initializer();
            }
        
            public ReadOnlyThreeDimensions(T[][][] arrayOfT)
            {
                _arrayOfT = arrayOfT;
            }
        
            public T this [int x, int y, int z]
            {
                get 
                {
                    return _arrayOfT[x][y][z];
                } 
            }
        }
        

        然后你只需要提供一些初始化方法,或者在静态构造函数中分配它。

        public static int[][][] IntInitializer()
        {
            return xyz // something that constructs a [][][]  
        }
        

        【讨论】:

        • 我认为这是正确的想法,尽管可以改进实现。一方面,如果您复制传入的数组,则可以更改原始数组。再说一次,如果数组是在构造过程中传入的文字,则无法从外部引用它们,因此没有理由复制。
        • 您可以随时更改该构造函数以创建一个新的 T[][][] 并复制所有值,但由于用例似乎只设置了一次,因此似乎没有必要.
        • Here's a similar approach,但使用字典作为底层数据类型
        【解决方案5】:

        枚举,当然。

        【讨论】:

        • 他想在多维表中查找值。您无法为此使用枚举。
        • 啊哈是的,这个问题突然变得更有意义了
        • 但我还是不明白这是怎么回事。无需让表格无法接受更新。他所要做的就是避免编写更新它的代码。
        • Peter,按照这个标准,像“const”和“readonly”这样的关键字应该被抛弃,对吧? :)
        • 我不会把它们扔掉的。它们是无害的,编译器是稳定的,对于某些代码来说,它代表了一个重大的变化。但你是对的,我一开始就不会添加它们。我一直发现一种语言对于可以表达的东西比什么不能表达的东西更有趣。
        【解决方案6】:

        好吧,我采用了以下方法,虽然读起来有点难看,但很容易编辑。

            public struct Something
            {
                public readonly int Number;
                public readonly string Name;
                public Something(int num, string name) { this.Number = num; this.Name = name; }
            }
        
            public readonly Something[] GlobalCollection = new Something[] 
            {
                new Something(1, "One"),
                new Something(2, "Two"),
            };
        

        【讨论】:

        • 这并不完全一致。 “只读”可以防止您将 GlobalCollection 换成另一个 Something[],但它不会阻止您换出 GlobalCollection[0] 或 [1]。
        猜你喜欢
        • 1970-01-01
        • 2020-10-09
        • 2020-01-29
        • 2011-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多