C # anahtarı deyimi sınırlamaları - neden?


141

Bir switch deyimi yazarken, case deyimlerinde neleri açabileceğiniz konusunda iki sınırlama var gibi görünüyor.

Örneğin (ve evet, biliyorum, bu tür bir şey yapıyorsanız muhtemelen nesne yönelimli (OO) mimarinizin iffy olduğu anlamına gelir - bu sadece tartışmalı bir örnek!),

  Type t = typeof(int);

  switch (t) {

    case typeof(int):
      Console.WriteLine("int!");
      break;

    case typeof(string):
      Console.WriteLine("string!");
      break;

    default:
      Console.WriteLine("unknown!");
      break;
  }

Burada switch () ifadesi 'beklenen bir integral türünde bir değer' ile, vaka ifadeleri 'Sabit bir değer bekleniyor' ile başarısız olur.

Bu kısıtlamalar neden uygulanmaktadır ve bunun altında yatan gerekçe nedir? Switch deyimi neden herhangi bir neden görmüyorum vardır yalnızca statik analiz yenik ve değer varlık açık yüzden (olduğunu, ilkel) ayrılmaz olmak zorundadır. Gerekçe nedir?



Yerleşik türleri açmak için başka bir seçenek TypeCode Enum kullanmaktır .
Erik Philips

Basitçe, bir ENUM oluşturun ve Switch durumunda NameOf kullanın. Dinamik bir değişken üzerinde sabit olarak çalışacaktır.
Vaibhav.Inspired

Yanıtlar:


99

Bu benim orijinal yazı, bazı tartışmalara yol açtı ... çünkü yanlış :

Geçiş deyimi, büyük bir if-else deyimi ile aynı şey değildir. Her vaka benzersiz olmalı ve statik olarak değerlendirilmelidir. Switch ifadesi, kaç vakanız olursa olsun sabit bir zaman dalı yapar. İf-else deyimi, doğru olanı bulana kadar her koşulu değerlendirir.


Aslında, C # switch deyimi olan değil , her zaman sabit bir zaman dalı.

Bazı durumlarda derleyici bir atlama tablosu kullanarak gerçekten sabit bir zaman dalı olan bir CIL anahtar deyimi kullanır. Bununla birlikte, Ivan Hamilton tarafından işaret edilen seyrek durumlarda derleyici tamamen başka bir şey üretebilir.

Bu aslında çeşitli C # anahtar ifadeleri, bazı seyrek, bazı yoğun ve ildasm.exe aracı ile ortaya çıkan CIL bakarak yazarak doğrulamak oldukça kolaydır.


4
Diğer cevaplarda (benimki de dahil) belirtildiği gibi, bu cevapta iddialar doğru değildir. Silme tavsiye ederim (eğer sadece bu (muhtemelen ortak) yanlış anlama zorlamaktan kaçınmak).
mweerden

Lütfen benim düşünceme göre, switch deyiminin sabit bir zaman dalı yaptığını gösterdiğim yerdeki yazıma bakınız.
Brian Ensink

Cevabınız için çok teşekkür ederim, Brian. Lütfen Ivan Hamilton'un cevabına bakınız ((48259) [ beta.stackoverflow.com/questions/44905/#48259] ). Kısacası: C # ifadesi ile aynı olmayan (CIL'in) switch talimatından bahsediyorsunuz switch.
mweerden

Derleyici de dizeleri açarken sabit zamanlı dallanma ürettiğini sanmıyorum.
Drew Noakes

Bu hala C # 7.0 anahtar durum ifadelerinde desen eşleştirme ile uygulanabilir mi?
B. Darren Olson

114

C # anahtarı ifadesini CIL anahtarı yönergesiyle karıştırmamak önemlidir.

CIL anahtarı, atlama adresleri kümesine bir dizin gerektiren bir atlama tablosudur.

Bu yalnızca C # anahtarının durumları bitişikse yararlıdır:

case 3: blah; break;
case 4: blah; break;
case 5: blah; break;

Ama eğer değilse çok az kullanım:

case 10: blah; break;
case 200: blah; break;
case 3000: blah; break;

(Sadece 3 yuva kullanılan bir tablo ~ 3000 girişe ihtiyacınız olacaktır)

Bitişik olmayan ifadelerde, derleyici, eğer başka değilse, doğrusal kontroller yapmaya başlayabilir.

Bitişik olmayan daha büyük ifade kümeleriyle, derleyici bir ikili ağaç aramasıyla ve son olarak eğer -eğer-if-else ise son birkaç öğeyle başlayabilir.

Bitişik öğelerin kümelerini içeren ifade kümeleriyle, derleyici ikili ağaç aramasını ve son olarak bir CIL anahtarını içerebilir.

Bu "mays" ve "sayılar" ile doludur ve derleyiciye bağlıdır (Mono veya Rotor ile farklılık gösterebilir).

Sonuçlarınızı bitişikteki durumları kullanarak makinemde çoğalttım:

10 yollu bir anahtar yürütmek için toplam süre, 10000 yineleme (ms):
10 yollu anahtar (ms) için yaklaşık 25.1383: 0.00251383

50 yollu anahtar yürütmek için toplam süre, 10000 yineleme (ms):
50 yollu anahtar (ms) başına 26.593 yaklaşık süre: 0.0026593

5000 yollu bir anahtar yürütmek için toplam süre, 10000 yineleme (ms):
5000 yollu anahtar (ms) için yaklaşık süre 23.7094: 0.00237094

50000 yollu anahtar yürütmek için toplam süre, 10000 yineleme (ms):
50000 yollu anahtar (ms) başına yaklaşık 20.0933: 0.00200933

Sonra da bitişik olmayan vaka ifadeleri kullanarak yaptım:

10 yollu anahtar yürütme için toplam süre, 10000 yineleme (ms):
10 yollu anahtar için yaklaşık süre (ms): 0.00196189

500 yollu anahtar için toplam süre, 10000 yineleme (ms):
500 yollu anahtar için yaklaşık süre (ms): 0.00191664

5000 yollu bir anahtar yürütmek için toplam süre, 10000 yineleme (ms):
5000 yollu anahtar (ms) için yaklaşık süre: 19.5871

Bitişik olmayan 50.000 büyük / küçük harf değişimi ifadesi derlenmez.
"Bir ifade 'ConsoleApplication1.Program.Main (string [])' yakınında derlemek için çok uzun veya karmaşık

Burada komik olan, ikili ağaç aramasının CIL anahtar komutundan biraz daha hızlı (muhtemelen istatistiksel olarak değil) görünmesidir.

Brian, hesaplamalı karmaşıklık teorisi açısından çok açık bir anlamı olan " sabit " kelimesini kullandınız . Basit bitişik tamsayı örneği O (1) (sabit) olarak kabul edilen CIL üretebilirken, seyrek bir örnek O (log n) (logaritmik), kümelenmiş örnekler arasında bir yerde bulunur ve küçük örnekler O (n) (doğrusaldır) ).

Bu, bir statikin Generic.Dictionary<string,int32>oluşturulabileceği String durumunu bile ele almaz ve ilk kullanımda belirli bir ek yüke maruz kalır. Buradaki performans, performansına bağlı olacaktır Generic.Dictionary.

Eğer işaretlerseniz C # dil belirtimi (değil CIL Spec) Eğer "15.7.2 switch deyimi" "sabit zaman" ifadesi yer almıyor yapar veya altta yatan uygulama bile CIL anahtarı talimatını kullandığı (varsayarak çok dikkatli olmak bulacaksınız bu tür şeyler).

Günün sonunda, modern bir sistemde bir tamsayı ifadesine karşı bir C # anahtarı, mikrosaniye altı bir işlemdir ve normalde endişelenmeye değmez.


Elbette bu zamanlar makinelere ve koşullara bağlı olacaktır. Bu zamanlama testlerine dikkat etmem, bahsettiğimiz mikrosaniye süreleri çalışmakta olan herhangi bir “gerçek” kod tarafından gölgelenir (ve bazı "gerçek kodları da eklemeniz gerekir, aksi takdirde derleyici dalı optimize eder) veya sistemde titreşim. Yanıtlarım C # derleyicisi tarafından oluşturulan CIL incelemek için IL DASM kullanarak dayanmaktadır . Tabii ki, bu nihai değildir, çünkü CPU'nun çalıştırdığı gerçek talimatlar JIT tarafından oluşturulur.

Aslında x86 makinemde yürütülen son CPU talimatlarını kontrol ettim ve basit bir bitişik set anahtarını aşağıdaki gibi bir şey yaparak onaylayabilirim:

  jmp     ds:300025F0[eax*4]

İkili ağaç araması aşağıdakilerle dolu olduğunda:

  cmp     ebx, 79Eh
  jg      3000352B
  cmp     ebx, 654h
  jg      300032BB
  
  cmp     ebx, 0F82h
  jz      30005EEE

Deneylerinizin sonuçları beni biraz şaşırttı. Seninkini Brian's ile değiştirdin mi? Sonuçları sizinkinde büyüklükte bir artış gösterir. Bir şey mi eksik? Her durumda, net cevap için teşekkürler.
mweerden

Böyle küçük bir işlemle zamanlamayı doğru bir şekilde hesaplamak zordur. Kodu veya test prosedürlerini paylaşmadık. Bitişik vakalar için zamanlarının neden artması gerektiğini göremiyorum. Benimki 10 kat daha hızlıydı, bu yüzden ortamlar ve test kodu büyük ölçüde değişebilir.
Ivan Hamilton

23

Akla ilk gelen neden tarihseldir :

Çoğu C, C ++ ve Java programcısı bu tür özgürlüklere alışık olmadığından, bunları talep etmezler.

Bir başka, daha geçerli neden, dil karmaşıklığının artmasıdır :

Her şeyden önce, nesneler operatörle mi .Equals()yoksa ==operatörle mi karşılaştırılmalıdır ? Her ikisi de bazı durumlarda geçerlidir. Bunu yapmak için yeni bir sözdizimi sunmalı mıyız? Programcının kendi karşılaştırma yöntemini sunmasına izin vermeli miyiz?

Ayrıca, nesnelerin açılmasına izin verilmesi , switch ifadesi ile ilgili temel varsayımları kırabilir . Anahtar deyiminin, nesnelerin açılmasına izin verilirse derleyicinin uygulayamayacağını belirleyen iki kural vardır (bkz. C # sürüm 3.0 dil belirtimi , §8.7.2):

  • Anahtar etiketlerinin değerlerinin sabit olması
  • Anahtar etiketlerinin değerleri farklıdır (böylece belirli bir anahtar ifadesi için yalnızca bir anahtar bloğu seçilebilir)

Sabit olmayan vaka değerlerine izin verildiği varsayımsal durumda bu kod örneğini göz önünde bulundurun:

void DoIt()
{
    String foo = "bar";
    Switch(foo, foo);
}

void Switch(String val1, String val2)
{
    switch ("bar")
    {
        // The compiler will not know that val1 and val2 are not distinct
        case val1:
            // Is this case block selected?
            break;
        case val2:
            // Or this one?
            break;
        case "bar":
            // Or perhaps this one?
            break;
    }
}

Kod ne yapacak? Olgu ifadeleri yeniden sıralanırsa ne olur? Gerçekten de, C # 'ın geçişi yasadışı hale getirmesinin nedenlerinden biri, geçiş deyimlerinin keyfi olarak yeniden düzenlenebilmesidir.

Bu kurallar bir nedenden dolayı mevcuttur - böylece programcı, bir vaka bloğuna bakarak bloğun girildiği kesin koşulu kesin olarak bilebilir. Yukarıda belirtilen anahtar ifadesi 100 satıra veya daha fazlasına (ve olacaktır) büyüdüğünde, bu tür bilgiler paha biçilmezdir.


2
Anahtar yeniden sıralama hakkında not. Vakada kod bulunmaması durumunda düşme yasaldır. Durum 1: Durum 2: Konsol.WriteLine ("Merhaba"); break;
Joel McBeth

10

Bu arada, aynı temel mimariye sahip olan VB, çok daha esnek Select Caseifadelere izin verir (yukarıdaki kod VB'de çalışacaktır) ve yine de bunun mümkün olduğu yerlerde verimli kod üretir, böylece teknik kısıtlamanın argümanı dikkatle düşünülmelidir.


1
Select CaseTr VB çok esnek ve süper bir zaman tasarrufu olduğunu. Çok özlüyorum.
Eduardo Molteni

@EduardoMolteni Sonra F # 'a geçin. Buna karşılık Pascal ve VB'nin anahtarları aptal çocuklara benziyor.
Luaan

10

Çoğunlukla, bu kısıtlamalar dil tasarımcıları nedeniyle uygulanmaktadır. Temel gerekçe, dil geçmişi, idealler veya derleyici tasarımının basitleştirilmesi ile uyumluluk olabilir.

Derleyici şunları seçebilir (ve yapar):

  • büyük bir if-else ifadesi oluştur
  • MSIL anahtar yönergesi kullanma (atlama tablosu)
  • bir Generic.Dictionary <string, int32> oluşturun, ilk kullanımda doldurun ve bir dizinin MSIL anahtar komutuna (atlama tablosu) geçmesi için Generic.Dictionary <> :: TryGetValue () öğesini çağırın.
  • if-elses ve MSIL "switch" atlamalarının bir kombinasyonunu kullanın

Anahtar deyimi sabit bir zaman dalı DEĞİLDİR. Derleyici kısa yollar bulabilir (karma kovalar, vb. Kullanarak), ancak daha karmaşık vakalar bazı durumlarda diğerlerinden daha erken dallanan daha karmaşık MSIL kodu oluşturur.

String örneğini işlemek için, derleyici a.Equals (b) (ve muhtemelen a.GetHashCode ()) kullanarak sona erer (bir noktada). Derleyicinin bu kısıtlamaları karşılayan herhangi bir nesneyi kullanmasının üç değer olacağını düşünüyorum.

Statik vaka ifadelerine duyulan ihtiyaca gelince ... vaka ifadeleri deterministik olmasaydı bu optimizasyonlardan bazıları (karma, önbellekleme, vb.) Kullanılamazdı. Ancak daha önce gördük ki, derleyici sadece eğer basitçe if-else-if-road'u zaten seçti ...

Edit: lomaxx - "typeof" işleci Anlayışınız doğru değil. "Typeof" işleci bir tür için System.Type nesnesini elde etmek için kullanılır (üst türleri veya arabirimleriyle ilgisi yoktur). Bir nesnenin belirli bir türle çalışma zamanı uyumluluğunu kontrol etmek "is" operatörünün işidir. Burada bir nesneyi ifade etmek için "typeof" kullanımı önemsizdir.


6

Konudayken, Jeff Atwood'a göre , switch ifadesi bir programlama vahşetidir . Onları idareli kullanın.

Aynı görevi bir tablo kullanarak da yapabilirsiniz. Örneğin:

var table = new Dictionary<Type, string>()
{
   { typeof(int), "it's an int!" }
   { typeof(string), "it's a string!" }
};

Type someType = typeof(int);
Console.WriteLine(table[someType]);

7
Ciddi bir şekilde kelepçeden Twitter gönderisinin bir kanıtı var mı? En azından güvenilir bir kaynakla bağlantı kurun.
Ivan Hamilton

4
Güvenilir bir kaynaktan; söz konusu Twitter yayını, baktığınız sitenin yazarı Jeff Atwood'dan. :-) Jeff merak ediyorsanız bu konuda bir avuç blog yazısı var.
Judah Gabriel Himango

Jeff BS'in yazıp yazmamasına bakılmaksızın toplam BS olduğuna inanıyorum. Switch deyiminin durum makinelerini ve bir enumtürün değerine göre değişen kod akışını değiştirmeye diğer örneklerini vermesi ne kadar komik . Ayrıca, bir enumtür değişkenini açtığınızda intellisense'nin otomatik olarak bir switch deyimi doldurması da tesadüf değildir .
Jonathon Reinhart

@JonathonReinhart Evet, bence bu nokta - polimorfik kodu işlemenin switchdeyimi kullanmaktan daha iyi yolları var . Devlet makineleri yazmamanız gerektiğini söylemiyor, sadece aynı şeyi güzel özel tipler kullanarak yapabileceğinizi söylüyor. Tabii ki, bu oldukça karmaşık durumları kolayca kapsayabilecek türlere sahip F # gibi dillerde çok daha kolaydır. Örneğin, durumun türün bir parçası haline geldiği ayrımcı sendikaları kullanabilir ve yerine switchdesen eşleşmesi kullanabilirsiniz. Veya örneğin arayüzler kullanın.
Luaan

Eski cevap / soru, ama (yanlış olursam beni düzeltin) Dictionaryoptimize edilmiş bir switchaçıklamadan oldukça yavaş olacağını düşünürdüm ...?
Paul

6

Switch deyiminin neden sadece statik analize geçmesi için bir neden görmüyorum

Doğru, o değil var etmek ve birçok dil gerçeği kullanımı dinamik anahtar tablolara yapmak. Ancak bu, "case" yan tümcelerini yeniden sıralamanın kodun davranışını değiştirebileceği anlamına gelir.

Burada "switch" e giren tasarım kararlarının arkasında bazı ilginç bilgiler var: C # switch deyimi neden düşmeye izin vermeyecek şekilde tasarlanmış ancak yine de mola gerektiriyor?

Dinamik vaka ifadelerine izin vermek, bu PHP kodu gibi canavarlıklara neden olabilir:

switch (true) {
    case a == 5:
        ...
        break;
    case b == 10:
        ...
        break;
}

açıkçası sadece if-elseifadeyi kullanmalıdır .


1
Bu PHP hakkında seviyorum (şimdi C # geçiş gibi), bu özgürlük. Bununla birlikte, kötü kod yazma özgürlüğü geliyor, ama bu gerçekten C # özledim bir şey
silkfire

5

Microsoft sonunda seni duydu!

Şimdi C # 7 ile şunları yapabilirsiniz:

switch(shape)
{
case Circle c:
    WriteLine($"circle with radius {c.Radius}");
    break;
case Rectangle s when (s.Length == s.Height):
    WriteLine($"{s.Length} x {s.Height} square");
    break;
case Rectangle r:
    WriteLine($"{r.Length} x {r.Height} rectangle");
    break;
default:
    WriteLine("<unknown shape>");
    break;
case null:
    throw new ArgumentNullException(nameof(shape));
}

3

Bu bir neden değildir, ancak C # spesifikasyon bölümü 8.7.2 aşağıdakileri belirtir:

Bir switch ifadesinin geçerli türü, switch ifadesi tarafından oluşturulur. Anahtar ifadesinin türü sbyte, bayt, kısa, ushort, int, uint, uzun, ulong, char, dize veya numaralandırma türündeyse, bu anahtar deyiminin yönetimsel türüdür. Aksi takdirde, anahtar ifadesinin türünden aşağıdaki olası yönetim türlerinden birine tam olarak bir kullanıcı tanımlı örtük dönüşüm (§6.4) bulunmalıdır: sbyte, bayt, kısa, ushort, int, uint, uzun, ulong, char, dize . Böyle bir örtük dönüştürme yoksa veya bu tür bir örtük dönüştürme birden fazla varsa, bir derleme zamanı hatası oluşur.

C # 3.0 belirtimi şu adreste bulunur: http://download.microsoft.com/download/3/8/8/388e7205-bc10-4226-b2a8-75351c669b09/CSharp%20Language%20Specification.doc


3

Yahuda'nın yukarıdaki cevabı bana bir fikir verdi. OP'nin yukarıdaki anahtar davranışını aşağıdakileri kullanarak "taklit edebilirsiniz" Dictionary<Type, Func<T>:

Dictionary<Type, Func<object, string,  string>> typeTable = new Dictionary<Type, Func<object, string, string>>();
typeTable.Add(typeof(int), (o, s) =>
                    {
                        return string.Format("{0}: {1}", s, o.ToString());
                    });

Bu, davranışı switch ifadesiyle aynı stilde bir türle ilişkilendirmenize olanak tanır. IL için derlendiğinde bir anahtar tarzı atlama masası yerine anahtarlı olmanın ek bir yararı olduğuna inanıyorum.


0

Derleyicinin switch deyiminizi otomatik olarak çevirememesinin temel bir nedeni olmadığını düşünüyorum:

if (t == typeof(int))
{
...
}
elseif (t == typeof(string))
{
...
}
...

Ama bundan pek bir şey kazanılmadı.

İntegral tiplerle ilgili bir vaka deyimi, derleyicinin bir dizi optimizasyon yapmasına izin verir:

  1. Çoğaltma yoktur (derleyicinin algıladığı vaka etiketlerini çoğaltmazsanız). Örneğinizde, kalıtım nedeniyle birden çok türle eşleşebilir. İlk maç yapılmalı mı? Hepsi?

  2. Derleyici, tüm karşılaştırmalardan kaçınmak için bir atlama tablosu ile integral tip üzerinde bir anahtar deyimi uygulamayı seçebilir. 0 ile 100 arasında tamsayı değerleri olan bir numaralandırmayı açıyorsanız, her anahtar deyimi için bir tane olmak üzere, içinde 100 işaretçi olan bir dizi oluşturur. Çalışma zamanında, açık olan tamsayı değerine göre diziden adresi arar. Bu, 100 karşılaştırma yapmaktan çok daha iyi çalışma zamanı performansı sağlar.


1
Burada dikkat edilmesi gereken önemli bir karmaşıklık olduğunu .NET bellek modeli (varsayımsal, geçersiz tam olarak eşdeğer değil pseudocode yapmak bazı güçlü garantileri vardır C # ) switch (t) { case typeof(int): ... }çeviri o değişken ima çünkü t gerekir için iki kez bellekten getirilemedi t != typeof(int)oysa ikincisi olur, (varsayılan olarak) her zaman t tam olarak bir kez okur . Bu fark, bu mükemmel garantilere dayanan eşzamanlı kodun doğruluğunu bozabilir. Bu konuda daha fazla bilgi için, bkz. Joe Duffy Windows'ta Eşzamanlı Programlama
Glenn Slayden

0

Anahtar deyimi belgelerine göre , nesneyi örtülü olarak integral türüne dönüştürmenin açık bir yolu varsa, buna izin verilir. Sanırım her durum ifadesi için onunla değiştirilecek bir davranış bekliyorsunuz if (t == typeof(int)), ancak bu operatörü aşırı yüklediğinizde bu solucan bütün bir kutu açar. == geçersiz kılma işleminizi yanlış yazarsanız, anahtar deyimi için uygulama ayrıntıları değiştiğinde davranış değişir. İntegral tipler ve string ile karşılaştırmaları ve integral tiplere indirgenebilecek (ve hedeflenen) şeyleri azaltarak potansiyel sorunlardan kaçınırlar.


0

yazdı:

"Switch deyimi, kaç vakanız olursa olsun sabit bir zaman dalı yapar."

Dil, dize türünün bir switch deyiminde kullanılmasına izin verdiğinden , derleyicinin bu tür için sabit bir zaman dalı uygulaması için kod üretemediğini ve bir if-then stili oluşturması gerektiğini varsayıyorum.

@mweerden - Ah anlıyorum. Teşekkürler.

C # ve .NET'te çok fazla deneyimim yok, ancak dil tasarımcıları dar koşullar dışında tip sistemine statik erişime izin vermiyor gibi görünüyor. Typeof bu çalışma zamanında sadece erişilebilir, böylece anahtar kelime bir nesne döndürür.


0

Bence Henk "tip sisteme sttatik erişim yok" şeyi ile çivilendi

Başka bir seçenek de, sayısal ve dizgilerin olabileceği türler için bir düzen bulunmamasıdır. Bu nedenle, bir tür anahtarı ikili bir arama ağacı oluşturamaz, yalnızca doğrusal bir arama oluşturur.


0

Bu yorumu , tablo odaklı bir yaklaşım kullanmanın genellikle daha iyi olduğu konusunda hemfikirim .

C # 1.0'da jenerik ve isimsiz delegeleri olmadığı için bu mümkün değildi. C # 'ın yeni sürümleri bu işi yapmak için iskeleye sahiptir. Nesne hazır bilgileri için bir gösterime sahip olmak da yardımcı olur.


0

C # hakkında neredeyse hiçbir bilgim yok, ancak her iki anahtarın daha genel hale getirmeyi düşünmeden diğer dillerde olduğu gibi alındığından şüpheleniyorum ya da geliştirici, genişletmenin buna değmeyeceğine karar verdi.

Kesinlikle söylemek gerekirse, bu kısıtlamaları koymak için hiçbir neden olmadığı konusunda kesinlikle haklısınız. Bunun nedeni, izin verilen durumlar için uygulamanın çok verimli (Brian Ensink ( 44921 ) tarafından önerildiği gibi ) olduğundan şüphelenebilir, ancak tamsayılar ve bazı rasgele durumlar kullanırsam uygulamanın çok verimli olduğundan (wrt if-statements) şüpheliyim (örneğin 345, -4574 ve 1234203). Ve her durumda, her şeye (veya en azından daha fazlasına) izin vermenin ve sadece belirli vakalar için (ardışık (neredeyse) ardışık sayılar gibi) etkili olduğunu söylemenin zararı nedir?

Ben, ancak, bir nedeni bu tür lomaxx (verdiği biri gibi nedenlerle türlerini hariç tutmak isteyebilirsiniz tahmin edebilirsiniz 44918 ).

Düzenleme: @Henk ( 44970 ): Dizeler en fazla paylaşılıyorsa, eşit içeriğe sahip dizeler de aynı bellek konumuna işaretçiler olacaktır. Ardından, durumlarda kullanılan dizelerin ardışık olarak bellekte saklandığından emin olursanız, anahtarı çok verimli bir şekilde uygulayabilirsiniz (yani, 2 karşılaştırma, bir ekleme ve iki atlama sırasıyla yürütme).


0

C # 8, bir anahtar ifadesi kullanarak bu sorunu zarif ve kompakt bir şekilde çözmenizi sağlar:

public string GetTypeName(object obj)
{
    return obj switch
    {
        int i => "Int32",
        string s => "String",
        { } => "Unknown",
        _ => throw new ArgumentNullException(nameof(obj))
    };
}

Sonuç olarak, şunları elde edersiniz:

Console.WriteLine(GetTypeName(obj: 1));           // Int32
Console.WriteLine(GetTypeName(obj: "string"));    // String
Console.WriteLine(GetTypeName(obj: 1.2));         // Unknown
Console.WriteLine(GetTypeName(obj: null));        // System.ArgumentNullException

Yeni özellik hakkında daha fazla bilgi edinebilirsiniz buradan edinebilirsiniz .

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.