Varsayılan dize başlatma: NULL veya Boş? [kapalı]


130

NULL değerinin olmaması ve "" veya String.Empty'nin geçerli bir değer olduğunu düşünerek dizelerimi her zaman NULL olarak başlattım. Son zamanlarda String.Empty'nin varsayılan değer olarak kabul edildiği veya hiçbir değeri temsil etmediği daha fazla kod örneği gördüm. Bu bana tuhaf geliyor, c # 'teki yeni eklenen boş değer atanabilir türlerle,' Değer Yok'u temsil etmek için NULL kullanmayarak dizelerle geriye doğru adımlar atıyoruz gibi görünüyor.

Varsayılan başlatıcı olarak ne kullanıyorsunuz ve neden?

Düzenleme: Cevaplara dayanarak daha fazla düşüncelerimi geliştirdim

  1. Hata işlemeyi önleme Değer null olmaması gerekiyorsa, neden NULLilk etapta ayarlandı ? Belki de hatayı, kod tabanınızın geri kalanını örtmek yerine, oluştuğu yerde tanımlamak daha iyi olur?

  2. Boş kontrollerden kaçınmak Eğer kodda boş kontroller yapmaktan sıkıldıysanız, boş kontrolleri soyutlamak daha iyi olmaz mı? Belki de dize yöntemlerini NULLgüvenli hale getirmek için sarın (veya uzatın!) ? Sürekli kullanırsanız String.Emptyve bir boş değer sisteminize girerse ne olur , yine de NULLkontrol eklemeye başlar mısınız?

Yardım edemem ama bunun tembellik olduğu fikrine dönüyorum. Herhangi bir DBA null, veritabanında '' yerine kullanırsanız size aptal olmanın dokuz yolunu tokatlayacaktır . Aynı ilkelerin programlamada da geçerli olduğunu düşünüyorum ve hiçbir değeri temsil String.Emptyetmekten ziyade kullanan, kafayı ters çeviren biri olmalı NULL.

ilgili sorular


"The Sane"? Tanıdığım bir Dana olmamalı.
vfilby

@Joel, kaç kişinin Zim veya GIR hakkında hiçbir fikri olmadığına şaşırıyorum Ben de bunu iğrenç bulan arkadaşlarımdan bazılarına hayret ediyorum. Bunun saf iyilik olduğunu söylemiyorum, ama orada harika mizah külçeleri var.
vfilby

Biliyorum, ama bazen aksini iddia etmek eğlencelidir.
Dana the Sane

1
MVC form koleksiyonlarında veya oturum değişkenlerinde bu problemle çok karşılaşıyorum, en kullanışlı şeyin null'u String.Empty'ye dönüştürmek olduğunu buldum. steno ve ardından gerekli olan dize işlemini uygulayın. Örneğin. (öğe ?? String.Empty) .Trim (). ToUpper ()
sonjz

4
bu yapıcı değil mi?
nawfal

Yanıtlar:


111

"Boş" ve NULL arasında ayrım yapmak için +1. "Boş" un "geçerli, ancak boş" anlamına gelmesi gerektiğini ve "BOŞ" un "geçersiz" anlamına gelmesi gerektiğini kabul ediyorum.

Bu yüzden soruna şöyle cevap verirdim:

Örneğin, bir kullanıcının ikinci adı gibi değiştirilebilen veya değiştirilemeyen geçerli bir varsayılan değer istediğimde boş .

Bir hata olduğunda, takip eden kod değeri açıkça ayarlamazsa NULL .


11
NULL ve boş arasında ayrım yapmak, ikisi arasında aslında bir fark olduğunda harikadır. Yine de, bir farkın olmadığı birçok durum vardır ve bu nedenle, aynı şeyi temsil etmenin iki yolu bir sorumluluktur.
Greg Smalter

6
@Greg: Çeşitliliğin kafa karışıklığı potansiyeli olduğunu kabul etsem de, aynı zamanda harika bir değer de olabilir. Geçerli ve geçersiz değerleri ayırt etmek için "" veya NULL yazmanın basit ve tutarlı kuralı, kodunuzun anlaşılmasını kolaylaştıracaktır. Bu nedenle, boole'leri her zaman "if (var)" ile, "if (var! = NULL)" ile işaretçiler ve "if (var! = 0)" ile tamsayılar ile test ediyorum - hepsi derleyici için aynı anlama geliyor, ancak kodumu koruyan zayıf geliştiriciye yardımcı olan ek bilgiler taşırlar.
Adam Liss

32

MSDN'ye göre :

Dizeleri Emptyyerine değerle nullbaşlatarak, NullReferenceExceptionmeydana gelme olasılığını azaltabilirsiniz .

IsNullOrEmpty()Yine de her zaman kullanmak iyi bir uygulamadır.


45
Sırf istisna olasılığını azaltıyor olmanız, istisnanın olmaması gerektiği anlamına gelmez. Kodunuz orada olan bir değere bağlıysa, bir istisna atmalıdır!
rmeador

1
Elbette, orada tartışma yok. OTOH, eğer dizeleri birbirine ekliyorsanız ... Bence bu kodlama tarzına, tecrübeye ve duruma bağlı.
Tomalak

Bu esas olarak kullandığım şey, hangisini kullanacağımı ayırt et.
PositiveGuy

3
Unutmayın IsNullOrWhiteSpace () for .NET framework 4+
Coops

13

Neden dizinizin sıfırlanmasını istiyorsunuz? Bir değişken tanımladığınızda bir değişkeni başlatmak zorunda değilsiniz ve IMO, bunu yalnızca atadığınız değer kod bloğu bağlamında geçerli olduğunda yapmalısınız.

Bunu çok görüyorum:

string name = null; // or String.Empty
if (condition)
{
  name = "foo";
}
else
{
  name = "bar";
}

return name;

Null olarak başlatmamak da aynı derecede etkili olacaktır. Ayrıca, çoğu zaman bir değerin atanmasını istersiniz. Null olarak başlatarak, bir değer atamayan kod yollarını potansiyel olarak kaçırabilirsiniz. Şöyle:

string name = null; // or String.Empty
if (condition)
{
  name = "foo";
}
else if (othercondition)
{
  name = "bar";
}

return name; //returns null when condition and othercondition are false

Null olarak başlatmadığınızda, derleyici tüm kod yollarının bir değer atamadığını söyleyen bir hata oluşturacaktır. Elbette bu çok basit bir örnek ...

Matthijs


Neredeyse her C # programcısının kullandığına inandığım Visual Studio'da, ikinci durumunuz (olmadan = null) tam olarak belirttiğiniz nedenle bir uyarı oluşturacaktır - bir dizenin varsayılan değerinin boş olup olmaması önemli değildir. Her kod yolu üzerinden bir atama garantisi vermezseniz, IDE (ve / veya temeldeki derleyicinin [?]) bir uyarı oluşturacaktır. Uyarılar derlemeyi engellemese de, hala oradalar - kolayca çözülenleri bırakmak, programcının dikkatini çekebilecek diğerlerini şaşırtmaya yardımcı olabilir
Code Jockey

Bildiğim kadarıyla, ilk durum nameto null(uyarı yok) olmadan tamamen mutlu olacak , çünkü her kod yolu bir değer atıyor name- orada başlatmaya gerek yok
Code Jockey

8

Gerçekte dizi işleme yazılımı olmayan çoğu yazılım için, program mantığı dize değişkenlerinin içeriğine bağlı olmamalıdır. Bir programda böyle bir şey gördüğümde:

if (s == "value")

İçimde kötü bir his var. Bu yöntemde neden bir dize değişmezi var? Ayar snedir? Mantığın dizenin değerine bağlı olduğunu biliyor mu? Çalışması için küçük harf olması gerektiğini biliyor mu? Kullanmak için değiştirerek bunu düzeltmeli miyim String.Compare? Bir oluşturmalı Enumve onu ayrıştırmalı mıyım ?

Bu perspektiften, oldukça basit bir kod felsefesine varılır: mümkün olan her yerde bir dizinin içeriğini incelemekten kaçınırsınız. Bir dizgeyi String.Emptykarşılaştırmak, onu birebir ile karşılaştırmanın gerçekten özel bir durumudur: gerçekten mecbur kalmadıkça yapmaktan kaçınmanız gereken bir şeydir.

Bunu bilerek, kod tabanımızda buna benzer bir şey gördüğümde gözümü kırpmam:

string msg = Validate(item);
if (msg != null)
{
   DisplayErrorMessage(msg);
   return;
}

Bunun Validateasla geri dönmeyeceğini biliyorum String.Empty, çünkü bundan daha iyi kod yazıyoruz.

Tabii ki, dünyanın geri kalanı böyle çalışmıyor. Programınız kullanıcı girdisi, veritabanları, dosyalar vb. İle uğraşırken, diğer felsefeleri de hesaba katmalısınız. Orada, kaosa düzen koymak kodunuzun görevidir. Bu düzenin bir kısmı, boş bir dizenin String.Emptyne zaman ve ne zaman ifade edilmesi gerektiğini bilmektir null.

(Sadece kıçımdan konuşmadığımdan emin olmak için, kod tabanımızda `String.IsNullOrEmpty 'aradım. 54 oluşumunun tümü, kullanıcı girdisini işleyen, Python komut dosyalarından değer döndüren, alınan değerleri inceleyen yöntemlerdedir. harici API'ler vb.)


6

Bu aslında C # dilinde açık bir boşluktur. Boş olamayacak bir dizge tanımlamanın bir yolu yoktur. Bu, tanımladığınız kadar basit sorunlara neden olur ve programcıları, çoğu durumda NULL ve String.Empty aynı anlama geldiğinden, vermek zorunda kalmamaları gereken bir karar vermeye zorlar. Bu da daha sonra diğer programcıları hem NULL hem de String.Empty işlemeye zorlayabilir ki bu sinir bozucudur.

Daha büyük bir sorun, veritabanlarının bir C # dizesiyle eşleşen alanları tanımlamanıza izin vermesidir, ancak veritabanı alanları NOT NULL olarak tanımlanabilir. Dolayısıyla, bir C # türü kullanarak SQL Server'da bir varchar (100) NOT NULL alanını doğru bir şekilde göstermenin bir yolu yoktur.

Spec # gibi diğer diller buna izin verir.

Benim düşünceme göre, C # 'ın null değerine izin vermeyen bir dizeyi tanımlayamaması, boşa izin veren bir int tanımlayamaması kadar kötüdür.

Sorunuzu tam olarak cevaplamak için: Varsayılan başlatma için her zaman boş dize kullanırım çünkü veritabanı veri türlerinin çalışma şekline daha benzer. (Düzenleme: Bu ifade çok açık değildi. "NULL gereksiz bir durum olduğunda varsayılan başlatma için boş dize kullanıyorum, tıpkı NULL gereksiz bir durum olacaksa bir veritabanı sütununu NOT NULL olarak ayarladığım gibi. , DB sütunlarımın çoğu NOT NULL olarak ayarlandı, bu yüzden bunları bir C # dizesine getirdiğimde, dize boş olacak veya bir değere sahip olacak, ancak hiçbir zaman NULL olmayacak. null, String.Empty'nin anlamından farklı bir anlama sahipse ve bu vakayı yaygın olandan daha az buluyorum (ancak buradaki insanlar bu vakanın meşru örneklerini verdiler). ")


String.Empty'yi kullanmak, yalnızca bir veritabanı dizesinin tanımlanma yöntemlerinden birine benzer . Hiçbir değeri temsil etmek için null kullanmak, null nvarchar ile çok daha uyumludur. Sanırım tuzuna değecek herhangi bir DBA, `` hiçbir değeri temsil etmemek için '' kullanırsanız size aptalca dokuz yolla tokat atar.
vfilby

Aslında, Greg, yanlış anladın. Bu, en az "veritabanı türlerinin nasıl çalıştığını" en az null değer atanamayan değer türleridir, çünkü bunlar hiçbir zaman bir null tutamaz ve bu nedenle hiçbir zaman null yapılabilir bir sütuna eşlenemez. Sözleşmede, herhangi bir dize herhangi bir varchar sütunuyla eşleşebilir.
Tor Haugen

Haklısın, son iddiam yeterince açık değildi. Çoğu zaman, veritabanı sütunlarım NULL DEĞİLDİR (çünkü boş dizge ile NULL arasında hiçbir fark olmayacaktır), bu yüzden dizelerimi hiçbir zaman boş değer saklamayarak benzer tutmaya çalışıyorum ve bunu kastettim.
Greg Smalter

5

Değişir.

Değerin eksik olup olmadığını anlayabilmeniz gerekiyor mu (tanımlanmaması mümkün müdür)?

Boş dize, bu dizenin kullanımı için geçerli bir değer mi?

Her ikisine de "evet" cevabını verdiyseniz, null kullanmak isteyeceksiniz. Aksi takdirde "değer yok" ve "boş dize" arasındaki farkı anlayamazsınız.

Değer olup olmadığını bilmeniz gerekmiyorsa, boş dizge muhtemelen daha güvenlidir, çünkü nerede kullanırsanız kullanın boş kontrolleri atlamanıza izin verir.



3

Ya "" ya da null olarak ayarlıyorum - her zaman String.IsNullOrEmpty kullanarak kontrol ederim, yani her ikisi de iyi.

Ama içimdeki inek, onun için uygun bir değere sahip olmadan önce onu sıfıra ayarlamam gerektiğini söylüyor ...



2

Bunun bir hata önleme tekniği olması mümkün mü (tavsiye edilebilir veya değil ..)? "" Hala bir dizge olduğu için, NULL olsaydı bir istisnaya neden olacak dize işlevlerini onun üzerinde çağırabilirsiniz.


1
Normalde duyduğum bahane bu, kulağa tembellik gibi geliyor. "Bu değeri kontrol etmeye zahmet etmek istemiyorum, bu yüzden bir kestirme yol alacağım" bana öyle geliyor.
vfilby

Evet, katılmıyorum. Hata denetimi kodunun miktarını azaltmanın iyi olduğu bazı durumlar olabilir, ancak hiçbir etkisi olmayan işlev çağrıları da
en iyisi

2

Onları her zaman olarak başlatırım NULL.

Ben her zamanstring.IsNullOrEmpty(someString) değerini kontrol etmek için kullanırım .

Basit.


1

Bu duruma bağlıdır. Çoğu durumda String.Empty kullanırım çünkü bir dizeyi her kullanmaya çalıştığımda boş kontroller yapmak istemiyorum. Bu, kodu çok daha basit hale getirir ve istenmeyen NullReferenceException çökmelerine neden olma olasılığınız azalır.

Dizeyi yalnızca ayarlanıp ayarlanmadığını ve boş bir dizenin onu ayarlamak için geçerli bir şey olduğunu bilmem gerektiğinde boş olarak ayarlıyorum. Pratikte bu durumları nadir buluyorum.


1

Boş dize bir değerdir (tesadüfen herhangi bir harf içermeyen bir metin parçası). Null, değer olmadığını belirtir.

Gerçek değerleri göstermediklerini veya içermediklerini belirtmek istediğimde değişkenleri boş olarak başlatırım - amaç değer yok ise.


1

Tomalak yanıtını tekrarlayarak, null değerinin başlangıç ​​değerine bir dize değişkeni atadığınızda, değişkeninizin artık bir dizge nesnesi olmadığını unutmayın; C # 'daki herhangi bir nesne ile aynı. Dolayısıyla, değişkeniniz için herhangi bir yönteme veya özelliğe erişmeye çalışırsanız ve bunun bir dize nesnesi olduğunu varsayarsanız, NullReferenceException istisnasını alırsınız.


1

Null, yalnızca bir değerin isteğe bağlı olduğu durumlarda kullanılmalıdır. Değer isteğe bağlı değilse ("Ad" veya "Adres" gibi), değer hiçbir zaman boş olmamalıdır. Bu, veritabanları, POCO'lar ve kullanıcı arayüzü için geçerlidir. Null, "bu değer isteğe bağlıdır ve şu anda yoktur" anlamına gelir.

Alanınız isteğe bağlı değilse, boş dize olarak başlatmalısınız. Onu boş olarak başlatmak, nesnenizi geçersiz bir duruma (kendi veri modeliniz tarafından geçersiz) yerleştirir.

Şahsen ben dizelerin varsayılan olarak boş değer atanmamasını tercih ederim, bunun yerine yalnızca bir "dizge?" Bildirirsek null yapılabilir. Belki bu daha derin bir düzeyde uygulanabilir veya mantıklı olmasa da; emin değil.



0

Atanmamış (veya bu yerde bir program akışı gerçekleşmeyen) bir değer için null kullanmamak için hiçbir neden olmadığını düşünüyorum. Ayırt etmek istiyorsanız, == null var. Sadece belirli bir değeri kontrol etmek istiyorsanız ve boş mu yoksa farklı bir şey mi olduğunu umursamıyorsanız, String.Equals ("XXX", MyStringVar) gayet iyi.

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.