Odpowiedzi:
Tak, ale musisz to zadeklarować readonly
zamiast const
:
public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
Powodem jest to, że const
można go zastosować tylko do pola, którego wartość jest znana w czasie kompilacji. Inicjalizator tablicy, który pokazałeś, nie jest stałym wyrażeniem w języku C #, więc powoduje błąd kompilatora.
Zadeklarowanie go readonly
rozwiązuje ten problem, ponieważ wartość nie jest inicjowana do czasu wykonania (chociaż gwarantuje się, że zainicjowała się przed pierwszym użyciem tablicy).
W zależności od tego, co ostatecznie chcesz osiągnąć, możesz również rozważyć deklarację wyliczenia:
public enum Titles { German, Spanish, Corrects, Wrongs };
readonly static
mieć dowolne podobieństwo do żądanej semantyki.
static
nie jest wymagane, aby działało, po prostu dodaje możliwość odwoływania się Titles
bez instancji, ale usuwa możliwość zmiany wartości dla różnych instancji (np. Możesz mieć konstruktor z parametrem w zależności od tego, którą wartość zmieniasz w tym readonly
polu).
Możesz zadeklarować tablicę jako readonly
, ale pamiętaj, że możesz zmienić element readonly
tablicy.
public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";
Rozważ użycie enum, jak sugerował Cody, lub IList.
public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
const
NIE readonly
...
Nie można utworzyć tablicy „const”, ponieważ tablice są obiektami i można je tworzyć tylko w czasie wykonywania, a stałe encje są rozwiązywane w czasie kompilacji.
Zamiast tego możesz zadeklarować tablicę jako „tylko do odczytu”. Ma to taki sam efekt jak const, z tą różnicą, że wartość można ustawić w czasie wykonywania. Można go ustawić tylko raz, a następnie jest to wartość tylko do odczytu (tj. Stała).
const int[] a = null;
niezbyt przydatny, ale rzeczywiście przykład stałej tablicowej.
Od wersji C # 6 możesz pisać w następujący sposób:
public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };
Zobacz także: C #: Nowy i ulepszony C # 6.0 (konkretnie rozdział „Funkcje i właściwości wyrażania”)
Spowoduje to utworzenie właściwości statycznej tylko do odczytu, ale nadal pozwoli ci zmienić zawartość zwracanej tablicy, ale gdy ponownie wywołasz właściwość, otrzymasz ponownie oryginalną, niezmienioną tablicę.
Dla wyjaśnienia, ten kod jest taki sam jak (lub w rzeczywistości skrót):
public static string[] Titles
{
get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}
Należy pamiętać, że takie podejście ma wadę: nowa tablica jest tworzona przy każdym odwołaniu, więc jeśli używasz bardzo dużej tablicy, może to nie być najbardziej wydajne rozwiązanie. Ale jeśli ponownie użyjesz tej samej tablicy (na przykład umieszczając ją w prywatnym atrybucie), ponownie otworzy ona możliwość zmiany zawartości tablicy.
Jeśli chcesz mieć niezmienną tablicę (lub listę), możesz również użyć:
public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };
Ale nadal wiąże się to z ryzykiem zmian, ponieważ nadal możesz rzutować go z powrotem na ciąg [] i modyfikować zawartość jako taką:
((string[]) Titles)[1] = "French";
Titles[0]
na przykład zostaniesz przypisany - w efekcie próba przypisania jest cicho ignorowana. W połączeniu z nieefektywnością ponownego tworzenia tablicy za każdym razem zastanawiam się, czy takie podejście jest w ogóle warte. Natomiast drugie podejście jest wydajne i musisz zejść z drogi, aby pokonać niezmienność.
Jeśli zadeklarujesz tablicę za interfejsem IReadOnlyList, otrzymasz stałą tablicę o stałych wartościach deklarowanych w czasie wykonywania:
public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };
Dostępne w .NET 4.5 i wyższych.
Rozwiązanie .NET Framework v4.5 +, które poprawia odpowiedź tdbeckett :
using System.Collections.ObjectModel;
// ...
public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);
Uwaga: Biorąc pod uwagę, że kolekcja jest stała koncepcyjnie, sensowne może static
być zadeklarowanie jej na poziomie klasy .
Powyższe:
Inicjuje niejawne pole zaplecza właściwości jeden raz z tablicą.
Zauważ, że { get; }
- tj. Deklarowanie tylko modułu pobierania właściwości - powoduje, że sama właściwość jest domyślnie tylko do odczytu (próba połączenia readonly
z nią { get; }
jest w rzeczywistości błędem składni).
Alternatywnie, możesz po prostu pominąć { get; }
i dodać, readonly
aby utworzyć pole zamiast właściwości, jak w pytaniu, ale ujawnianie publicznych elementów danych jako właściwości zamiast pól jest dobrym nawykiem do tworzenia.
Tworzy array- jak struktury (pozwalając indeksowanego dostępu ), który jest naprawdę solidnie i tylko do odczytu (koncepcyjnie stały, raz utworzone), zarówno w odniesieniu do:
IReadOnlyList<T>
roztworu, gdzie obsada może być wykorzystywane w celu uzyskania dostępu do zapisu elementów , jak pokazano na pomocne odpowiedzi mjepsen męska .
Ta sama luka dotyczy w interfejsie , który, mimo podobieństwa w nazwie do klasy , nie obsługuje nawet dostępu indeksowanego , przez co zasadniczo nie nadaje się do zapewniania dostępu podobnego do tablicy).(string[])
IReadOnlyCollection<T>
ReadOnlyCollection
IReadOnlyCollection
nie obsługuje dostępu indeksowanego, więc nie można go tutaj użyć. Dodatkowo, podobnie jak IReadOnlyList
(który ma dostęp zindeksowany) jest podatny na manipulowanie elementami poprzez rzutowanie z powrotem na string[]
. Innymi słowy: ReadOnlyCollection
(na które nie można rzutować tablicy ciągów) jest najbardziej niezawodnym rozwiązaniem. Nieużywanie gettera jest opcją (i zaktualizowałem odpowiedź, aby to zauważyć), ale w przypadku danych publicznych prawdopodobnie lepiej trzymać się właściwości.
Na moje potrzeby określam static
tablicę zamiast niemożliwej const
i działa ona:
public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
const
z przykładu OP również działa, ale to (lub twoja odpowiedź) pozwala zmienić zarówno: Titles
instancję, jak i dowolną wartość. Jaki jest sens tej odpowiedzi?
readonly
const
/ readonly
rozważania, po prostu dzięki czemu działa (jak gdyby const
był to błąd składni). Dla niektórych osób wydaje się to być cenną odpowiedzią (być może próbowali również const
przez pomyłkę?).
Możesz zastosować inne podejście: zdefiniuj stały ciąg reprezentujący tablicę, a następnie podziel ciąg na tablicę, gdy jej potrzebujesz, np.
const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');
Takie podejście daje stałą, którą można zapisać w konfiguracji i w razie potrzeby przekształcić w tablicę.
W trosce o kompletność, teraz mamy do dyspozycji również ImmutableArrays. To powinno być naprawdę niezmienne:
public readonly static ImmutableArray<string> Tiles = ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });
Wymaga System.Collections.Immutable odniesienia NuGet
https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx
Jest to sposób na robienie tego, co chcesz:
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}
Jest to bardzo podobne do robienia tablicy tylko do odczytu.
public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
; nie ma potrzeby ponownego tworzenia listy przy każdym pobieraniu, jeśli i tak zostanie to ReadOnlyCollection.
To jedyna poprawna odpowiedź. Obecnie nie możesz tego zrobić.
Wszystkie pozostałe odpowiedzi sugerują użycie statycznych zmiennych tylko do odczytu, które są podobne , ale nie takie same jak stała. Stała jest na stałe zakodowana w zestawie. Statyczną zmienną tylko do odczytu można ustawić raz, prawdopodobnie podczas inicjalizacji obiektu.
Czasami są one wymienne, ale nie zawsze.
Alternatywnie, aby obejść problem z elementami, które można modyfikować za pomocą tablicy tylko do odczytu, można zamiast tego użyć właściwości statycznej. (Poszczególne elementy można nadal zmieniać, ale zmiany te zostaną wprowadzone tylko w lokalnej kopii tablicy).
public static string[] Titles
{
get
{
return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
}
}
Oczywiście nie będzie to szczególnie wydajne, ponieważ za każdym razem tworzona jest nowa tablica ciągów.
Najlepsza alternatywa:
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 };