Sabit dizi bildirme


459

Aşağıdakine benzer bir şey yazmak mümkün mü?

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

static kullanılabilir, public static string [] Titles = new string [] {"German", "Spanish"};
Ray

Yanıtlar:


692

Evet, ama readonlyyerine beyan etmelisiniz const:

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

Bunun nedeni constsadece değeri derleme zamanında bilinen bir alana uygulanabilmesidir. Gösterdiğiniz dizi başlatıcısı C # 'da sabit bir ifade değildir, bu yüzden bir derleyici hatası üretir.

O bildirilmesi readonly(tertibin kullanılması ilk önce başlatılır olduğu garanti olsa da) bir değer kadar çalıştırma başlatıldı değildir, çünkü bu sorunu çözer.

Sonuçta ne elde etmek istediğinize bağlı olarak, bir numaralandırma bildirmeyi de düşünebilirsiniz:

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

115
Buradaki dizinin salt okunur olmadığını unutmayın ; Başlıklar [2] = "Gal"; zamanında iyi çalışır
Marc Gravell

46
Muhtemelen de statik olmasını istersiniz
timtam

4
sınıfta değil, bir yöntem gövdesinde "const" dizisi bildirmeye ne dersiniz?
serhio

19
Aşağı oy için özür dilerim, ama const da statik anlamına gelir. Diziyi salt okunur olarak bildirmek geçici bir çözüme yakın değildir. olması gerekenden readonly staticistenen semantik herhangi bir benzerlik var.
Anton

4
@Anton, siz ve "takipçileriniz" inilen oyu kaldırdınız mı? staticÇalışması için bana gerekli değil, sadece Titlesörnek olmadan başvuru yapma imkanı ekler , ancak farklı örnekler için değeri değiştirme olasılığını kaldırır (örneğin, o readonlyalanın değerini değiştirdiğinize bağlı olarak parametreyle yapıcıya sahip olabilirsiniz ).
Sinatr

58

Diziyi şu şekilde bildirebilirsiniz readonly, ancak readonlydizi öğesini değiştirebileceğinizi unutmayın .

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

Cody'nin önerdiği gibi enum veya IList kullanmayı düşün.

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

31
.NET 4.5 ve sonraki sürümlerde bir listeyi IList <string> yerine IReadOnlyList <string> olarak bildirebilirsiniz.
Grzegorz Smulko

Açık olmak gerekirse, yine de bir IReadOnlyList içindeki değerleri değiştirebilirsiniz (sadece eleman eklemeyin veya kaldırmayın). Ama evet, bunu IReadOnlyList olarak ilan etmek bir IList'ten daha iyi olurdu.
KevinVictor

Soru constDEĞİL hakkında readonly...
Yousha Aleayoub

51

Bir 'const' dizisi oluşturamazsınız çünkü diziler nesnedir ve yalnızca çalışma zamanında oluşturulabilir ve const varlıkları derleme zamanında çözülür.

Bunun yerine dizinizi "salt okunur" olarak bildirmektir. Bu, const ile aynı etkiye sahiptir, ancak değer çalışma zamanında ayarlanabilir. Sadece bir kez ayarlanabilir ve daha sonra salt okunur (yani sabit) bir değerdir.


2
Bu gönderi, dizilerin neden sabit olarak bildirilemediğini vurgular
Radderz

1
Sabit bir dizi bildirmek mümkündür; sorun sabit bir değerle başlatmaktır. Akla gelen tek çalışan örnek, const int[] a = null;çok yararlı olmayan, ama aslında bir dizi sabitinin bir örneğidir.
waldrumpus

BU tek doğru cevaptır.
Yousha Aleayoub

17

C # 6'dan beri şöyle yazabilirsiniz:

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

Ayrıca bkz: C #: Yeni ve Geliştirilmiş C # 6.0 (özellikle "İfade Gövdeli İşlevler ve Özellikler" bölümü)

Bu salt okunur bir statik özellik oluşturur, ancak yine de döndürülen dizinin içeriğini değiştirmenize izin verir, ancak özelliği yeniden çağırdığınızda, orijinal, değiştirilmemiş diziyi tekrar alırsınız.

Açıklığa kavuşturmak için, bu kod (veya aslında kısayol) ile aynıdır:

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

Lütfen bu yaklaşımın bir dezavantajı olduğunu unutmayın: Her referansta yeni bir dizi başlatılır, bu nedenle çok büyük bir dizi kullanıyorsanız, bu en etkili çözüm olmayabilir. Ancak aynı diziyi yeniden kullanırsanız (örneğin özel bir özniteliğe koyarak) dizinin içeriğini değiştirme olasılığını tekrar açacaktır.

Değişmez bir diziye (veya listeye) sahip olmak istiyorsanız şunları da kullanabilirsiniz:

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

Ancak, yine de bir dizgiye [] geri döndürebileceğiniz ve içeriği değiştirebileceğiniz için, bunun yine de değişiklik riski vardır:

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

1
Bu durumda alan yerine mülk kullanmanın karı nedir?
nicolay.anykienko

2
Alan her çağrıda yeni bir nesne döndüremez. Bir özellik temel olarak bir tür "kılık değiştirmiş işlevdir".
mjepson

1
Son seçeneğe başvuruyorsanız, bu hem alan hem de mülk kullanılarak yapılabilir, ancak herkese açık olduğu için bir Mülkü tercih ederim. Mülklerin piyasaya sürülmesinden bu yana asla kamusal bir alan kullanmıyorum.
mjepson

1
1. yaklaşımın başka bir dezavantajı daha vardır: Titles[0]Örneğin, aslında atama girişimi sessizce göz ardı edilirse bir derleme hatası almazsınız . Diziyi her seferinde yeniden yaratmanın verimsizliğiyle birlikte, bu yaklaşımın gösterilmeye değer olup olmadığını merak ediyorum. Aksine, 2. yaklaşım etkilidir ve değişmezliği yenmek için kendi yolunuzdan çıkmanız gerekir.
mklement0

6

IReadOnlyList arabiriminin arkasında bir dizi bildirirseniz, çalışma zamanında bildirilen sabit değerlere sahip sabit bir dizi alırsınız:

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

.NET 4.5 ve sonraki sürümlerinde kullanılabilir.


6

TDBeckett'in cevabını geliştiren bir .NET Framework v4.5 + çözümü :

using System.Collections.ObjectModel;

// ...

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

Not: Koleksiyonun kavramsal olarak sabit olduğu düşünüldüğünde, onu sınıf düzeyinde staticbeyan etmek mantıklı olabilir .

Yukarıdaki:

  • Özelliğin örtülü yedekleme alanını bir kez diziyle başlatır .

    • Not o { get; }- yani sadece bir özellik ilan getter - örtük salt okunur özelliğini kendisi kılan (birleştirmeye çalışıyor readonlyile { get; }aslında bir yazım hatasıdır).

    • Alternatif olarak, sorudaki gibi bir özellik yerine bir alan oluşturmak için atlayabilir { get; }ve ekleyebilirsiniz , ancak genel veri üyelerini alanlar yerine özellikler olarak göstermeniz iyi bir alışkanlıktır.readonly

  • Her ikisi de şunlarla ilgili olarak gerçekten ve sağlam bir şekilde salt okunur (kavramsal olarak sabit, oluşturulduktan sonra sabit ) olan dizi benzeri bir yapı oluşturur ( dizinli erişime izin verir ) :

    • koleksiyonun bir bütün olarak değiştirilmesini önleme (örneğin, öğeleri kaldırarak veya ekleyerek veya değişkene yeni bir koleksiyon atayarak).
    • bireysel elemanların değiştirilmesini önleme .
      (Hatta dolaylı değişiklik mümkün değildir - bir ile farklı IReadOnlyList<T>solüsyon, bir (string[])döküm elemanları yazma erişimi kazanmak için kullanılabilir gösterildiği gibi, mjepsen en yararlı cevap .
      Aynı açığı için de geçerlidir arayüzünde , adı aynı olsa da, hangi için sınıf , hatta desteklemez dizinlenmiş erişim erişim dizi benzeri sağlamak için temelde uygunsuz hale.)IReadOnlyCollection<T> ReadOnlyCollection

1
@mortb: Maalesef IReadOnlyCollectiondizine eklenen erişimi desteklemediğinden burada kullanılamaz. Ek olarak, IReadOnlyList(endeksli erişimi olan) gibi, geri dönerek eleman manipülasyonuna açıktır string[]. Başka bir deyişle: ReadOnlyCollection(bir dize dizisini yayınlayamayacağınız) en sağlam çözümdür. Bir alıcı kullanmamak bir seçenektir (ve bunu not etmek için cevabı güncelledim), ancak genel verilerle bir mülke bağlı kalmak daha iyidir.
mklement0

5

Benim ihtiyaçları staticiçin imkansız yerine dizi tanımlamak constve çalışır: public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };


1
constOP örneğinden kaldırmanız da işe yarar, ancak bu (veya cevabınız) hem Titlesörneği hem de herhangi bir değeri değiştirmeye izin verir . Peki bu cevabın anlamı nedir?
Sinatr

@Sinatr, bunu 3 yıl önce C # 'da çalışmaya başladığımda cevapladım. Onu bıraktım, şimdi Java dünyasındayım. Belki de eklemeyi unuttumreadonly
ALZ

İkinci düşünceden sonra, cevabınız OP kodunu herhangi bir const/ readonlydikkate almadan, nasıl çalıştıracağınız ( constsözdizimi hatasıymış gibi) doğrudan. Bazı insanlar için değerli bir cevap gibi görünüyor (belki de constyanlışlıkla kullanmaya çalıştılar mı?).
Mart'ta Sinatr

5

Farklı bir yaklaşım kullanabilirsiniz: dizinizi temsil etmek için sabit bir dize tanımlayın ve ardından dizeyi ihtiyacınız olduğunda bir diziye bölün;

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

Bu yaklaşım size konfigürasyonda saklanabilen ve gerektiğinde bir diziye dönüştürülebilen bir sabit verir.


8
Bence bölünmenin gerçekleştirilmesinin maliyeti, const'un tanımlanmasıyla sağlanan faydalardan çok daha fazladır. Ama benzersiz bir yaklaşım ve kutunun dışında düşünmek için +1! ;)
Radderz

Aynı çözümü göndermek üzereydim ve daha sonra bunu gördüm, sert ve olumsuz açıklamaların aksine, bu aslında bir Özniteliğe bir const iletmek için gerekli olan senaryom için mükemmeldi ve sonra öznitelik yapıcısındaki değeri bölüyorum ihtiyacım olanı al. ve her örnek için öznitelikler oluşturulmadığından, performans maliyetine sahip olmasının hiçbir nedenini göremiyorum.
Kalpesh Popat


3

Bu, istediğinizi yapmanın bir yoludur:

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

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

Salt okunur bir dizi yapmaya çok benzer.


8
Bunu sadece şu şekilde yapabilirsiniz public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();; Zaten bir ReadOnlyCollection yaparsanız, her almada listeyi yeniden oluşturmanız gerekmez.
Nyerguds

3

Tek doğru cevap bu. Şu anda bunu yapamazsınız.

Diğer tüm cevaplar, bir sabite benzeyen fakat aynı olmayan statik salt okunur değişkenlerin kullanılmasını önermektedir . Bir sabit, düzeneğe sert kodlanmıştır. Statik salt okunur bir değişken bir kez ayarlanabilir, muhtemelen bir nesne başlatıldığında.

Bunlar bazen değiştirilebilir, ancak her zaman değil.


2

Ben sadece onu salt okunur yapabileceğine inanıyorum.


2

Diziler muhtemelen yalnızca çalışma zamanında değerlendirilebilen şeylerden biridir. Sabitler derleme zamanında değerlendirilmelidir. "Const" yerine "salt okunur" kullanmayı deneyin.


0

Alternatif olarak, salt okunur bir diziyle değiştirilebilen öğelerle ilgili sorunu gidermek için bunun yerine statik bir özellik kullanabilirsiniz. (Tek tek öğeler yine de değiştirilebilir, ancak bu değişiklikler yalnızca dizinin yerel kopyasında yapılacaktır.)

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

Tabii ki, her seferinde yeni bir dize dizisi oluşturulduğundan bu özellikle etkili olmayacaktır.


0

En iyi alternatif:

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 };
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.