Câu trả lời:
Có, nhưng bạn cần khai báo readonly
thay vì const
:
public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
Lý do là const
chỉ có thể được áp dụng cho một trường có giá trị được biết tại thời điểm biên dịch. Trình khởi tạo mảng bạn đã hiển thị không phải là biểu thức không đổi trong C #, do đó, nó tạo ra lỗi trình biên dịch.
Khai báo nó readonly
giải quyết vấn đề đó bởi vì giá trị không được khởi tạo cho đến thời gian chạy (mặc dù nó được đảm bảo đã khởi tạo trước khi sử dụng mảng lần đầu tiên).
Tùy thuộc vào những gì cuối cùng bạn muốn đạt được, bạn cũng có thể xem xét khai báo một enum:
public enum Titles { German, Spanish, Corrects, Wrongs };
readonly static
có bất kỳ sự tương đồng với ngữ nghĩa được yêu cầu.
static
không bắt buộc phải làm cho nó hoạt động, nó chỉ thêm khả năng tham chiếu Titles
mà không có cá thể, nhưng loại bỏ khả năng thay đổi giá trị cho các trường hợp khác nhau (ví dụ: bạn có thể có hàm tạo với tham số tùy thuộc vào việc bạn thay đổi giá trị của readonly
trường đó ).
Bạn có thể khai báo mảng là readonly
, nhưng hãy nhớ rằng bạn có thể thay đổi thành phần của readonly
mảng.
public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";
Cân nhắc sử dụng enum, như Cody đề xuất hoặc IList.
public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
const
KHÔNG readonly
...
Bạn không thể tạo mảng 'const' vì mảng là đối tượng và chỉ có thể được tạo khi chạy và các thực thể const được giải quyết tại thời điểm biên dịch.
Thay vào đó, những gì bạn có thể làm là khai báo mảng của bạn là "chỉ đọc". Điều này có tác dụng tương tự như const ngoại trừ giá trị có thể được đặt trong thời gian chạy. Nó chỉ có thể được đặt một lần và sau đó là giá trị chỉ đọc (tức là const).
const int[] a = null;
trong đầu là không hữu ích lắm, nhưng thực sự là một thể hiện của hằng số mảng.
Vì C # 6, bạn có thể viết nó như sau:
public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };
Xem thêm: C #: C # 6.0 mới và được cải tiến (cụ thể là chương "Các thuộc tính và chức năng cơ thể biểu hiện")
Điều này sẽ tạo một thuộc tính tĩnh chỉ đọc, nhưng nó vẫn sẽ cho phép bạn thay đổi nội dung của mảng được trả về, nhưng khi bạn gọi lại thuộc tính đó, bạn sẽ nhận được mảng ban đầu, không thay đổi.
Để làm rõ, mã này giống như (hoặc thực tế là một tốc ký cho):
public static string[] Titles
{
get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}
Xin lưu ý rằng có một nhược điểm của phương pháp này: Một mảng mới thực sự được khởi tạo trên mỗi tham chiếu, vì vậy nếu bạn đang sử dụng một mảng rất lớn, đây có thể không phải là giải pháp hiệu quả nhất. Nhưng nếu bạn sử dụng lại cùng một mảng (bằng cách đặt nó vào một thuộc tính riêng), nó sẽ lại mở ra khả năng thay đổi nội dung của mảng.
Nếu bạn muốn có một mảng (hoặc danh sách) bất biến, bạn cũng có thể sử dụng:
public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };
Nhưng, điều này vẫn có rủi ro cho các thay đổi, vì bạn vẫn có thể chuyển nó trở lại chuỗi [] và thay đổi nội dung, như sau:
((string[]) Titles)[1] = "French";
Titles[0]
cho - chẳng hạn, thực tế, nỗ lực chuyển nhượng bị bỏ qua lặng lẽ. Kết hợp với việc không hiệu quả trong việc tạo lại mảng mỗi lần, tôi tự hỏi liệu cách tiếp cận này có đáng để hiển thị hay không. Ngược lại, cách tiếp cận thứ 2 là hiệu quả, và bạn phải đi ra ngoài để đánh bại sự bất biến.
Nếu bạn khai báo một mảng phía sau giao diện IReadOnlyList, bạn sẽ nhận được một mảng không đổi với các giá trị không đổi được khai báo khi chạy:
public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };
Có sẵn trong .NET 4.5 trở lên.
Một giải pháp .NET Framework v4.5 + cải thiện câu trả lời của tdbeckett :
using System.Collections.ObjectModel;
// ...
public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);
Lưu ý: Cho rằng bộ sưu tập là hằng số về mặt khái niệm, có thể có ý nghĩa để làm cho nó static
khai báo nó ở cấp độ lớp .
Ở trên:
Khởi tạo trường sao lưu ngầm của thuộc tính một lần với mảng.
Lưu ý rằng { get; }
- tức là, chỉ khai báo một getter thuộc tính - là điều làm cho chính thuộc tính đó hoàn toàn chỉ đọc (cố gắng kết hợp readonly
với { get; }
thực sự là một lỗi cú pháp).
Ngoài ra, bạn chỉ có thể bỏ qua { get; }
và thêm readonly
để tạo một trường thay vì thuộc tính, như trong câu hỏi, nhưng để lộ các thành viên dữ liệu công khai dưới dạng các thuộc tính thay vì các trường là một thói quen tốt để hình thành.
Tạo cấu trúc giống như mảng (cho phép truy cập được lập chỉ mục ) thực sự chỉ đọc và mạnh mẽ (không đổi về mặt khái niệm, một khi được tạo), cả hai đều liên quan đến:
IReadOnlyList<T>
giải pháp, mà một (string[])
diễn viên có thể được sử dụng để đạt được ghi vào các yếu tố , như trong câu trả lời hữu ích mjepsen của . IReadOnlyCollection<T>
giao diện , trong đó, bất chấp sự giống nhau trong tên đến lớp ReadOnlyCollection
, thậm chí không hỗ trợ truy cập được lập chỉ mục , về cơ bản không phù hợp để cung cấp quyền truy cập giống như mảng.)IReadOnlyCollection
không hỗ trợ truy cập được lập chỉ mục, vì vậy nó không thể được sử dụng ở đây. Ngoài ra, giống như IReadOnlyList
(có quyền truy cập được lập chỉ mục), nó dễ bị thao túng phần tử bằng cách chuyển trở lại string[]
. Nói cách khác: ReadOnlyCollection
(mà bạn không thể truyền một chuỗi chuỗi thành) là giải pháp mạnh mẽ nhất. Không sử dụng getter là một tùy chọn (và tôi đã cập nhật câu trả lời để lưu ý điều đó), nhưng với dữ liệu công khai , có lẽ tốt hơn để gắn bó với một tài sản.
Đối với nhu cầu của tôi, tôi xác định static
mảng, thay vì không thể const
và nó hoạt động:
public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
const
khỏi ví dụ OP cũng hoạt động, nhưng điều đó (hoặc câu trả lời của bạn) cho phép thay đổi cả: Titles
thể hiện và bất kỳ giá trị nào. Vì vậy, điểm trong câu trả lời này là gì?
readonly
const
/ readonly
cân nhắc nào, chỉ đơn giản là làm cho nó hoạt động (như nếu const
là một lỗi cú pháp). Đối với một số người, nó dường như là một câu trả lời có giá trị (có lẽ họ cũng đã cố gắng sử dụng const
do nhầm lẫn?).
Bạn có thể thực hiện một cách tiếp cận khác: xác định một chuỗi không đổi để biểu diễn mảng của bạn và sau đó chia chuỗi thành một mảng khi bạn cần, ví dụ:
const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');
Cách tiếp cận này cung cấp cho bạn một hằng số có thể được lưu trữ trong cấu hình và được chuyển đổi thành một mảng khi cần thiết.
Để hoàn thiện, bây giờ chúng tôi cũng có quyền sở hữu bất động sản. Điều này nên thực sự bất biến:
public readonly static ImmutableArray<string> Tiles = ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });
Yêu cầu tham chiếu System.Collections.Immutable NuGet
https://msdn.microsoft.com/en-us/l Library / mt52182 (v = vs.111) .aspx
Đây là một cách để làm những gì bạn muốn:
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}
Nó rất giống với việc thực hiện một mảng chỉ đọc.
public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
; không cần phải tạo lại danh sách trên mỗi lần truy xuất nếu bạn đặt nó thành ReadOnlyCollection.
Đây là câu trả lời đúng duy nhất. Bạn hiện không thể làm điều này.
Tất cả các câu trả lời khác đang đề xuất sử dụng các biến chỉ đọc tĩnh tương tự , nhưng không giống với hằng số. Một hằng số được mã hóa cứng vào lắp ráp. Một biến chỉ đọc tĩnh có thể thiết lập được một lần, có thể là một đối tượng được khởi tạo.
Chúng đôi khi có thể thay thế cho nhau, nhưng không phải lúc nào cũng vậy.
Thay vào đó, để giải quyết vấn đề có thể sửa đổi thành phần với mảng chỉ đọc, bạn có thể sử dụng thuộc tính tĩnh thay thế. (Các phần tử riêng lẻ vẫn có thể được thay đổi, nhưng những thay đổi này sẽ chỉ được thực hiện trên bản sao cục bộ của mảng.)
public static string[] Titles
{
get
{
return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
}
}
Tất nhiên, điều này sẽ không đặc biệt hiệu quả vì một mảng chuỗi mới được tạo ra mỗi lần.
Thay thế tốt nhất:
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 };