Burada iki sorun vardır: 1) bir Tür'ün null olup olmadığını test etmek; ve 2) bir nesnenin boş bir Türü temsil edip etmediğini görmek için test.
Sayı 1 (Bir Türü test etme) için, kendi sistemlerimde kullandığım bir çözüm var: TypeIsNullable-check solution
Sorun 2 için (bir nesneyi test etmek), yukarıdaki Dean Chalk'ın çözümü değer türleri için çalışır, ancak <T> aşırı yükünü kullanmak her zaman yanlış döndürdüğünden referans türleri için çalışmaz. Referans türleri doğası gereği geçersiz kılınabildiğinden, bir referans türünün test edilmesi her zaman true değerini döndürmelidir. Lütfen bu anlambilimin açıklaması için aşağıdaki [Hakkında "nullabilite" hakkında notuna bakın. Böylece, Dean'in yaklaşımında yaptığım değişiklik:
public static bool IsObjectNullable<T>(T obj)
{
// If the parameter-Type is a reference type, or if the parameter is null, then the object is always nullable
if (!typeof(T).IsValueType || obj == null)
return true;
// Since the object passed is a ValueType, and it is not null, it cannot be a nullable object
return false;
}
public static bool IsObjectNullable<T>(T? obj) where T : struct
{
// Always return true, since the object-type passed is guaranteed by the compiler to always be nullable
return true;
}
Ve yukarıdaki çözüm için istemci-test kodunda yaptığım değişiklik:
int a = 123;
int? b = null;
object c = new object();
object d = null;
int? e = 456;
var f = (int?)789;
string g = "something";
bool isnullable = IsObjectNullable(a); // false
isnullable = IsObjectNullable(b); // true
isnullable = IsObjectNullable(c); // true
isnullable = IsObjectNullable(d); // true
isnullable = IsObjectNullable(e); // true
isnullable = IsObjectNullable(f); // true
isnullable = IsObjectNullable(g); // true
Dean'in IsObjectNullable <T> (T t) yaklaşımını değiştirmemizin nedeni, orijinal yaklaşımının bir referans türü için her zaman yanlış döndürmesidir. IsObjectNullable gibi bir yöntemin başvuru türü değerlerini işleyebilmesi ve tüm başvuru türlerinin doğası gereği geçersiz olduğu için, başvuru türü ya da null değeri iletilirse, yöntem her zaman true değerini döndürmelidir.
Yukarıdaki iki yöntem aşağıdaki tek yöntemle değiştirilebilir ve aynı çıktıyı elde edebilir:
public static bool IsObjectNullable<T>(T obj)
{
Type argType = typeof(T);
if (!argType.IsValueType || obj == null)
return true;
return argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(Nullable<>);
}
Ancak, bu son tek yöntem yaklaşımıyla ilgili sorun, Nullable <T> parametresi kullanıldığında performansın düşmesidir. IsObjectNullable çağrısında Nullable <T> tipi bir parametre kullanıldığında, derleyicinin daha önce gösterilen ikinci yöntem aşırı yüklenmesini seçmesine izin vermek için bu tek yöntemin son satırının yürütülmesi işlemciden çok daha fazla zaman alır. Bu nedenle, optimum çözüm burada gösterilen iki yöntemli yaklaşımı kullanmaktır.
CAVEAT: Bu yöntem yalnızca örneklerde gösterildiği gibi orijinal nesne başvurusu veya tam bir kopya kullanılarak çağrıldığında güvenilir bir şekilde çalışır. Ancak, null olabilecek bir nesne orijinal Nullable <> formunda kalmak yerine başka bir Türde (nesne vb.) Kutulanmışsa, bu yöntem güvenilir bir şekilde çalışmaz. Bu yöntemi çağıran kod orijinal, kutulanmamış nesne başvurusu veya tam bir kopya kullanmıyorsa, bu yöntemi kullanarak nesnenin nullabilitesini güvenilir bir şekilde belirleyemez.
Kodlama senaryolarının çoğunda, nullabiliteyi belirlemek için bunun yerine referansı değil, orijinal nesnenin Tipini test etmek gerekir (örn., Nullabiliteyi belirlemek için kodun nesnenin orijinal Tipine erişimi olmalıdır). Bu daha yaygın durumlarda, IsTypeNullable (bağlantıya bakın), güvenlik açığını belirlemek için güvenilir bir yöntemdir.
PS - "nullability" hakkında
Ayrı bir gönderide yaptığım nullabilite hakkında doğrudan bu konuyu doğru bir şekilde ele alan bir beyanı tekrarlamalıyım. Yani, burada tartışmanın odağı, bir nesnenin genel Nullable türü olup olmadığını görmek için nasıl kontrol edilmesi gerektiğine değil, daha ziyade, türünün bir nesnesine null değeri atayabilip atamayacağına inanıyorum. Başka bir deyişle, bir nesne türünün null edilebilir olup olmadığını, Nullable olup olmadığını belirlememiz gerektiğini düşünüyorum. Aradaki fark semantik, yani nullabiliteyi belirlemek için pratik nedenlerdir, ki bu genellikle önemlidir.
Çalışma zamanına kadar bilinmeyen türlerde nesneler kullanan bir sistemde (web hizmetleri, uzaktan aramalar, veritabanları, beslemeler vb.), Ortak bir gereksinim, nesneye bir boş değer atanıp atanamayacağını veya nesnenin içerip içermeyebileceğini belirlemektir. boş. Null edilemeyen türlerde bu tür işlemlerin gerçekleştirilmesi, hem performans hem de kodlama gereksinimleri açısından çok pahalı olan hatalar, genellikle istisnalar olabilir. Bu tür problemleri proaktif bir şekilde önleme konusunda oldukça tercih edilen yaklaşımı kabul etmek için, keyfi bir Tipteki bir nesnenin null içerebildiğini belirlemek gerekir; yani, genellikle 'geçersiz' olup olmadığı.
Çok pratik ve tipik bir anlamda, .NET terimlerindeki kuralsızlık, bir nesnenin Türünün Null olabilecek bir form olduğu anlamına gelmez. Aslında birçok durumda, nesnelerin referans türleri vardır, boş değer içerebilir ve bu nedenle tümü boştur; bunların hiçbiri Nullable tipine sahip değildir. Bu nedenle, çoğu senaryoda pratik amaçlar için, genel kural dışılık kavramı ile uygulamaya bağlı Nullable kavramının karşılaştırılması için testler yapılmalıdır. Bu nedenle, yalnızca .NET Nullable türüne odaklanarak kapatılmamalı, bunun yerine, gereklilikleri ve davranışları hakkındaki anlayışımızı genel, pratik nullabilite kavramına odaklanma sürecine dahil etmeliyiz.