Bilindiği gibi değişken tipleri, depolanma durumları ve davranışları bakımından değer ve referans olmak üzere ikiye ayrılır. Bu iki veri tipi arasındaki önemli bir farktan bahsedeceğiz; referans türlerinin null(nothing) değeri alabiliyorken değer türlerinin bu özelliği taşımıyor olmasıdır. Yani değer türleri, her zaman bir değer taşımak zorundadır. Bir değişkenin, null olması, herhangi bir nesneye işaret etmiyor olduğu anlamına gelir. Özellikle veritabanı işlemlerinde null tabanlı kolonlarla çalışıldığında veya uygulama içerisinde değişkenlerin herhangi bir değer taşımaması gereken durumlarda bu özellik önem kazanmaktadır. Örneğin boolean türünde bir değişkenin değerini veritabanına göndereceğimizi düşünelim. Kullanıcı bu değeri, ya false ya da true olarak set edecektir. Peki, kullanıcının bu değeri set etmeden önce bu değişkenin default değeri ne olacak veya kullanıcı hiçbir şekilde bu değişkenin değerini set etmediyse veritabanına hangi değer gönderilecek.
Dim Sonuc1 As Boolean Dim Sonuc2 As Boolean = Nothing Console.WriteLine(Sonuc1) 'False Console.WriteLine(Sonuc2) 'False
VB.NET tarafında görüldüğü gibi Sonuc2 değişkeni Nothing olarak set edildiği halde false değerini taşımaktadır. C# tarafında bu şekilde bir tanımlama hataya neden olacaktır.
bool Sonuc1; //Use of unassigned local variable 'Sonuc' bool Sonuc2 = null; //Cannot convert null to 'bool' because it is a value type
.NET 2.0 ile birlikte bu sorun aşıldı ve değer türlerinin null değerini alabilmeleri sağlandı. Generic tip temelini kullanan bu türler, nullable(null değer alabilen) olarak tanımlanır.
VB.NET tarafında Int, char, double gibi değer türlerini nullable yapabilmek için değişkenler, System.Nullable(Of T As Structure) türünde tanımlanır. Burada T parametresi değer türünün adını temsil eder. Aşağıdaki satırlarda null değer alabilen üç farklı değer türünde değişken tanımlanmıştır;
Dim Tarih As Nullable(Of DateTime) Dim Yas As Nullable(Of Integer) Dim Sonuc As Nullable(Of Boolean)
C# tarafında Int, char, double gibi değer türlerini nullable yapabilmek için türün yanına “?” simgesi eklenir. Aşağıdaki satırlarda null değer alabilen üç farklı değer türünde değişken tanımlanmıştır;
DateTime? Tarih = null; int? Yas = null; bool? Sonuc = null;
Nullable değer türlerinin değer içerip içermediğini kontrol etmek için System.Nullable structure’in HasValue property’si kullanılır.
If Tarih.HasValue Then 'İşlem End If if (Tarih.HasValue) { //İşlem }
Nullable değer türleriyle ilgili diğer notlar aşağıda özetlenmiştir;
Referans türleri halihazırda null değeri desteklediği için nullable türünde tanımlamazlar.
Nullable değişkeninin değerini denetlemek için GetValueOrDefault() metodu ve HasValue, Value propertyleri kullanılır. System.Nullable.GetValueOrDefault() metodu, nullable türünün null(Nothing) olduğu durumlarda o anki veya default değerini döndürür.
Dim X As Nullable(Of Integer) = 10 Dim Y As Nullable(Of Integer) = 20 Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y) 'X:[10] , Y:[20] Y = X.GetValueOrDefault() Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y) 'X:[10] , Y:[10] X = Nothing Y = X.GetValueOrDefault() Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y) 'X:[] , Y:[0] X = 10 : Y = 20 Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y) 'X:[10] , Y:[20] Y = X.GetValueOrDefault(15)'Default değer atanmıştır Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y) 'X:[10] , Y:[10] X = Nothing Y = X.GetValueOrDefault(14) Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y) 'X:[] , Y:[14]
int? X = 10; int? Y = 20; Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y); //X:[10] , Y:[20] Y = X.GetValueOrDefault(); Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y); //X:[10] , Y:[10] X = null; Y = X.GetValueOrDefault(); Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y); //X:[] , Y:[0] X = 10 ; Y = 20; Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y); //X:[10] , Y:[20] Y = X.GetValueOrDefault(15);//Default değer atanmıştır Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y); //X:[10] , Y:[10] X = null; Y = X.GetValueOrDefault(14); Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y); //X:[] , Y:[14]
Nullable değer türlerinin Value property’si read-only olup değişkenin null olmadığı durumdaki değerini döndürür. Değişken, null iken value property’si çağrıldığı zaman System.InvalidOperationException hatası oluşur.
Konuyla ilgili olarak C# tarafında birkaç madde daha yazabiliriz;
Nullable ile non-nullable türler arasında büyüklük ve küçüklük durumlarına göre implicit veya explicit dönüşüm yapılabilir;
int StandardInteger = 45; int? NullableInteger; decimal StandardDecimal = 2.75M; // Int -> Int? implicit dönüşüm NullableInteger = StandardInteger; //Int? -> Int explicit dönüşüm StandardInteger = (int)NullableInteger; //Decimal -> Int? explicit döünşüm NullableInteger = (int?)StandardDecimal;
Nullable numerik türündeki değişkenler üzerinde aritmetik işlemler yapıldığı zaman değişkenlerin null olup olmamasına bağlı olarak sonuç değişir;
int? X = 15; int? Y = null; int? Sonuc; Sonuc = X * 3; //Sonuc = 45 Sonuc = X * Y; //Sonuc= null
C# tarafındaki diğer önemli gelişme nullable değişkenler için “??” operatörünün(Null Coalescing Operator) geliştirilmiş olmasıdır. Bu operatör, uygulandığı değişkenin null olup olmadığını kontrol eder eğer null ise koşulda verilmiş değer değilse değişkenin oanki değeri geriye döndürülür.
int? X = 10;int Y; Y = X ?? 15; Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y); //X:[10] , Y:[10] X = null; Y = X ?? 15; Console.WriteLine("X:[{0}] , Y:[{1}]", X, Y); //X:[] , Y:[15]
Nullable veri tipi kullanmanın performansa bir etkisi varmı
Bu soru birçok programcıyı meşgul etmiştir. Bu konuda detaylı test yapmamış olsam da kabaca şunu söyleyebiliriz. Bu türlerin doğaları itibariyle değer türleri(value type) kadar performanslı olması beklenmemeli. Nullable türleri üzerinde işlemler yapılacak değişkenler için kullanmak pek mantıklı olmaz. Eğer mutlaka işlem yapılacaksa HasValue özelliğinin kullanılarak değerinin normal bir değer türüne aktarılması performansı iyileştirebilir. Bu türleri veritabanı işlemlerinde tercih etmek daha doğru olacaktır. Yine de stack tabanlı olmalarından dolayı Nullable değişkenlerin daha önce kullanılan “boxed value type” yönteminden daha performanslı ve kullanışlı olduğunu söyleyebiliriz.
Ahmet hocam sonsuz teşekkür ediyorum, bu nothing ve null meselesi veritabanı gönderimlerinde bana çok sıkıntı yaşattı, şu makalenizle konuyu çözmüş olduk, başarılar dilerim…