簡體   English   中英

聲明一個常量數組

[英]Declare a const array

是否可以編寫類似於以下內容的內容?

public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

是的,但您需要將其聲明為readonly而不是const

public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

原因是const只能應用於其值在編譯時已知的字段。 您展示的數組初始值設定項不是 C# 中的常量表達式,因此會產生編譯器錯誤。

將其聲明為readonly可以解決該問題,因為該值直到運行時才會初始化(盡管它保證在第一次使用數組之前已初始化)。

根據您最終想要實現的目標,您還可以考慮聲明一個枚舉:

public enum Titles { German, Spanish, Corrects, Wrongs };

您可以將數組聲明為readonly ,但請記住,您可以更改readonly數組的元素。

public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";

考慮使用枚舉,如 Cody 建議的,或 IList。

public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();

您不能創建“const”數組,因為數組是對象,只能在運行時創建,而 const 實體在編譯時解析。

您可以做的是將您的數組聲明為“只讀”。 除了可以在運行時設置值之外,這與 const 具有相同的效果。 它只能設置一次,此后它是只讀(即常量)值。

從 C# 6 開始,你可以這樣寫:

public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };

另請參閱: C#:新的和改進的 C# 6.0 (特別是“Expression Bodied Functions and Properties”一章)

這將創建一個只讀的靜態屬性,但它仍然允許您更改返回的數組的內容,但是當您再次調用該屬性時,您將再次獲得原始的、未更改的數組。

為了澄清起見,此代碼與(或實際上是其簡寫)相同:

public static string[] Titles
{
    get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}

請注意,這種方法有一個缺點:一個新數組實際上是在每個引用上實例化的,所以如果您使用一個非常大的數組,這可能不是最有效的解決方案。 但是,如果您重新使用相同的數組(例如通過將其放入私有屬性中),它將再次打開更改數組內容的可能性。

如果你想要一個不可變的數組(或列表),你也可以使用:

public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };

但是,這仍然存在更改的風險,因為您仍然可以將其轉換回 string[] 並更改內容,如下所示:

((string[]) Titles)[1] = "French";

這是唯一正確的答案。 您目前無法執行此操作。

所有其他答案都建議使用類似於 的靜態只讀變量,但與常量不同。 常量被硬編碼到程序集中。 靜態只讀變量可設置一次,可能是在初始化對象時。

這些有時可以互換,但並非總是如此。

編輯:我想我會把這個扔進去,因為似乎問這個問題的人對數組有點模糊。 當您聲明一個數組時,它是一個指向包含該數組的內存段的指針。 它非常簡單,它只是一個地址,沒有復雜的邏輯控制它是否可讀或可寫。 它給了你一個指針,你可以用它做任何你想做的事。

這就是為什么制作不可變數組有點棘手的部分原因。 您可以編寫一個包裝數組的類,並且只允許通過返回副本來讀取它,但它實際上不再只是一個數組。

有些人建議使用 static 或 readonly 來模擬如果可以創建 const 數組時會看到的行為。 這些有一些副作用,對普通讀者來說可能並不明顯。

要真正獲得 const 數組,需要更新 C# 和 MSIL 底層代碼,以允許從數組讀取,但不允許寫入。

改進了tdbeckett 答案的.NET Framework v4.5+ 解決方案

using System.Collections.ObjectModel;

// ...

public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
  new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);

注意:鑒於集合在概念上是常量,在級別將其聲明為static可能是有意義的。

以上:

  • 使用數組初始化屬性的隱式支持字段一次

    • 請注意{ get; } { get; } - 即,只聲明一個屬性getter - 是什么使屬性本身隱式只讀(試圖將readonly{ get; }結合實際上是一個語法錯誤)。

    • 或者,您可以省略{ get; } { get; }並添加readonly創建領域,而不是一個屬性,如問題,但暴露公共數據成員的屬性,而不是場是一個好習慣的形成。

  • 創建一個類似數組的結構(允許索引訪問),它是真正且健壯的只讀(概念上不變,一旦創建),兩者都涉及:

    • 防止整個集合的修改(例如通過刪除或添加元素,或通過將新集合分配給變量)。
    • 防止修改單個元素
      (即使是間接修改也是不可能的 - 與IReadOnlyList<T>解決方案不同,其中(string[])可用於獲得對元素的寫訪問權限,如mjepsen 的有用答案所示
      相同的漏洞適用於IReadOnlyCollection<T>接口,盡管名稱與ReadOnlyCollection相似,但它甚至不支持索引訪問,因此從根本上不適合提供類似數組的訪問。)

如果你在 IReadOnlyList 接口后面聲明一個數組,你會得到一個在運行時聲明的具有常量值的常量數組:

public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };

在 .NET 4.5 及更高版本中可用。

您可以采用不同的方法:定義一個常量字符串來表示您的數組,然后在需要時將該字符串拆分為一個數組,例如

const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');

這種方法為您提供了一個常量,可以將其存儲在配置中並在需要時轉換為數組。

為了完整起見,現在我們還可以使用 ImmutableArrays。 這應該是真正不可變的:

public readonly static ImmutableArray<string> Tiles = ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });

需要 System.Collections.Immutable NuGet 參考

https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx

為了我的需要,我定義了static數組,而不是不可能的const ,它可以工作: public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

這是一種做你想做的事情的方法:

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}

它與做一個只讀數組非常相似。

我相信你只能讓它只讀。

數組可能是只能在運行時評估的事物之一。 必須在編譯時評估常量。 嘗試使用“只讀”而不是“常量”。

作為替代方案,要解決只讀數組的元素可以修改問題,您可以改用靜態屬性。 (仍然可以更改單個元素,但這些更改只會在數組的本地副本上進行。)

public static string[] Titles 
{
    get
    {
        return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
    }
}

當然,這不會特別有效,因為每次都會創建一個新的字符串數組。

最佳選擇:

public static readonly byte[] ZeroHash = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

快速解決方法,以防它對某人有幫助。 我需要一個string[]作為 Attribute 的參數(在某些理論中為測試用例傳遞內聯數據)。 readonly在這里沒有幫助。 但是,我最終做了:

const string foo = "a|b|c";

[InlineData(foo)]
public void Test(string fooString)
{
    var foo = fooString.Split("|"); // foo == {"a","b","c"}
    ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM