Bir nesnenin sıfırlanabilir olup olmadığı nasıl kontrol edilir?


204

Belirli bir nesnenin nullable olup olmadığını nasıl kontrol edebilirim, başka bir deyişle aşağıdaki yöntemin nasıl uygulanacağı ...

bool IsNullableValueType(object o)
{
    ...
}

EDIT: Null değer değer türleri arıyorum. Aklımda ref türleri yoktu.

//Note: This is just a sample. The code has been simplified 
//to fit in a post.

public class BoolContainer
{
    bool? myBool = true;
}

var bc = new BoolContainer();

const BindingFlags bindingFlags = BindingFlags.Public
                        | BindingFlags.NonPublic
                        | BindingFlags.Instance
                        ;


object obj;
object o = (object)bc;

foreach (var fieldInfo in o.GetType().GetFields(bindingFlags))
{
    obj = (object)fieldInfo.GetValue(o);
}

obj, şimdi eşit değere sahip type bool( System.Boolean) nesnesini ifade eder true. Gerçekten istediğim türden bir nesneydiNullable<bool>

Bu yüzden şimdi bir çalışma olarak o nullable olup olmadığını kontrol etmeye ve obj etrafında nullable bir sarıcı oluşturmak karar verdi.


Kod null olabilecek dizeleri içermeli mi? Bunlar, nullable gibi görünen jenerik olmayan bir ValueType'tır. Yoksa bir ValueType değil mi?
TamusJRoyce

Dize bir ValueType değil. Bir Referans türüdür.
Suncat2000

Bu gerçekten iyi bir soru! 'Type.IsNullableType ()' bir tür aldatmacadır, çünkü aslında yalnızca bir boş değer kabul edebilecek herhangi bir türü denetlemek istiyorsanız beklenen sonuçları döndürmeyen 'Nullable <T>' türünü denetler. değeri (örneğin, a.IsNullableType () ile kullanmaya çalıştım, burada 'a' çalışma zamanında belirlenen bir 'typeof (string)' idi)
ErrCode

Yanıt fieldInfo.FieldType içinde: FieldType'ın genel ve genel türün Nullable <> türünde olup olmadığını kontrol edin. (Örnek: if (FieldType.IsGenericType && FieldType.GetGenericTypeDefinition () == typeof (Nullable <>))). Nulllable <T> değişken T UndelyingSystemType (objektif <Boolean> yerine Boolean türünde) olacak obj.GetType () elde etmeye çalışmayın, bu bir boks sorunudur.
SoLaR

Yanıtlar:


273

İki tür null edilebilir Nullable<T>ve başvuru türü vardır.

Jon beni kutladığında yazmanın zor olduğunu düzeltti, ancak jeneriklerle yapabilirsiniz: - peki aşağıda. Bu aslında test tipidir T, ancak objparametreyi yalnızca genel tür çıkarımı için (aramayı kolaylaştırmak için) kullanmak - yine de objparametre olmadan neredeyse aynı şekilde çalışır .

static bool IsNullable<T>(T obj)
{
    if (obj == null) return true; // obvious
    Type type = typeof(T);
    if (!type.IsValueType) return true; // ref-type
    if (Nullable.GetUnderlyingType(type) != null) return true; // Nullable<T>
    return false; // value-type
}

Ancak, değeri bir nesne değişkenine zaten kutladıysanız, bu iyi çalışmaz.

Microsoft belgeleri: https://docs.microsoft.com/tr-tr/dotnet/csharp/programming-guide/nullable-types/how-to-identify-a-nullable-type


7
Son satır, yalnızca doğrudan T'ye boks yapmak yerine bir şekilde kutulu Nullable <T> almayı başarırsanız geçerlidir. Hatırlıyorum.
Jon Skeet

Bu kod kutulu bir Nullable <T> var çünkü değil, genel bir WPF dönüştürücü temel sınıf yazıyor ve bazı özellikleri nulllable, çünkü benim için yararlı oldu, bu yüzden bu durumda ve Activator.CreateInstance algılamak için Nullable.GetUnderlyingType kullandım kutulu bir nulllable, (Convert.ChangeType nullables btw'yi işlemez).
Qwertie

1
@Abel referans türlerini dikkate almadığını açıklığa kavuşturmak için yaptığı düzenlemeyi yeniden kastediyorsanız, cevabımın bu düzenlemeyi önceden yazdığını düşünüyorum ; okuyucu kendi ihtiyaçlarına göre orada kendi kararlarını verebilir, şüpheliyim (doğruladı: yorumu yeniden ref-türleri 14: 42'de eklendi; cevabım hepsi <= 14:34)
Marc Gravell

1
Obj = 1 olduğunda (obj == null) bir istisna atar mı?
Qi Fan

3
@JustinMorgan Sınırlandırılmış Tgenel bir parametreyse T : struct, Tizin verilmez Nullable<>, bu durumda bu durumda bir kontrol yapmanız gerekmez! Tür Nullable<>bir yapı olduğunu biliyorum , ama C # kısıtlama where T : structözellikle boş değer değer türlerini hariç. Spesifikasyon şöyle diyor: "Bir değer türü olarak sınıflandırılmasına rağmen null olabilecek bir türün (§4.1.10) değer türü kısıtlamasını karşılamadığını unutmayın."
Jeppe Stig Nielsen

46

Aşırı yükleme yöntemini kullanan çok basit bir çözüm var

http://deanchalk.com/is-it-nullable/

alıntı:

public static class ValueTypeHelper
{
    public static bool IsNullable<T>(T t) { return false; }
    public static bool IsNullable<T>(T? t) where T : struct { return true; }
}

sonra

static void Main(string[] args)
{
    int a = 123;
    int? b = null;
    object c = new object();
    object d = null;
    int? e = 456;
    var f = (int?)789;
    bool result1 = ValueTypeHelper.IsNullable(a); // false
    bool result2 = ValueTypeHelper.IsNullable(b); // true
    bool result3 = ValueTypeHelper.IsNullable(c); // false
    bool result4 = ValueTypeHelper.IsNullable(d); // false
    bool result5 = ValueTypeHelper.IsNullable(e); // true
    bool result6 = ValueTypeHelper.IsNullable(f); // true

7
artı bir tane sizin için test senaryoları eklemek için efendim. Bu test senaryolarını diğer tüm cevapları kontrol etmek için kullandım. Daha fazla insan bu ekstra biti gitmeli.
Marty Neal

4
Değer için, bu VB.NET'te çalışmaz. Geri döndürülecek tüm durumlarda " Aşırı yük çözünürlüğü başarısız oldu, çünkü bu argümanlar için erişilebilir 'IsNullable' en belirgin olanı değil " derleyici hatasıyla sonuçlanırTrue .
ckittel

1
Bu çözümü gerçekten çok seviyorum - ve VB'nin üstesinden gelemediği utanç verici. ValueType ile uğraşmayı denedim ama paylaşılan bir yöntem veya bir uzantı olarak adlandırılmış olup olmadığına bağlı olarak hangi aşırı yüklenmeyi kullanmak için VB derleyici ile ilgili tutarsız olması ile sorun yaşadım, hatta garip göründüğü gibi bu konuda bir soru kaldırdı: stackoverflow.com/ sorular / 12319591 /…
James Close

22
Derleme zamanı türünü denetliyorsunuz , ancak derleme zamanı türünün geçersiz ( System.Nullable<>) olduğu zaten açıktır (akıllıca ). Eğer derseniz object g = e;ve sonra ValueTypeHelper.IsNullable(g)ne elde etmeyi umuyorsunuz?
Jeppe Stig Nielsen

18
Az önce doğruladım; Jeppe'nin dediği gibi bu işe yaramıyor . Değişkenler nesneye dökülürse, her zaman false döndürür. Böylece, çalışma zamanında bilinmeyen bir nesnenin türünü bu şekilde belirleyemezsiniz. Bu çalışmanın tek zamanı, tür derleme zamanında sabitlenmişse ve bu durumda hiç bir çalışma zamanı denetimine gerek duymamanızdır.
HugoRune

30

"Bir türün null edilebilir olup olmadığı nasıl kontrol edilir?" aslında "Bir türün Nullable<>yapılıp yapılmadığı nasıl kontrol edilir ?", " Bir türün genel bir türden oluşturulmuş bir tür olup olmadığı nasıl kontrol edilir ?" şeklinde genelleştirilebilir, böylece yalnızca " Nullable<int>Bir Nullable<>? aynı zamanda " List<int>bir List<>mi?".

Sağlanan çözümün çoğu, Nullable.GetUnderlyingType()sadece vaka ile çalışacak yöntemi kullanır Nullable<>. Herhangi bir jenerik tiple çalışacak genel yansıtıcı çözümü görmedim, bu yüzden bu soru çoktan önce cevaplanmış olmasına rağmen, buraya gelecek nesiller için eklemeye karar verdim.

Bir türün Nullable<>yansıma kullanmanın bir biçimi olup olmadığını kontrol etmek için , önce yapılandırılmış genel türünüzü, örneğin Nullable<int>genel tür tanımına dönüştürmeniz gerekir Nullable<>. Bunu sınıfın GetGenericTypeDefinition()yöntemini kullanarak yapabilirsiniz Type. Ardından, elde edilen türü aşağıdakilerle karşılaştırabilirsiniz Nullable<>:

Type typeToTest = typeof(Nullable<int>);
bool isNullable = typeToTest.GetGenericTypeDefinition() == typeof(Nullable<>);
// isNullable == true

Aynısı herhangi bir genel tipe uygulanabilir:

Type typeToTest = typeof(List<int>);
bool isList = typeToTest.GetGenericTypeDefinition() == typeof(List<>);
// isList == true

Birkaç tür aynı görünebilir, ancak farklı sayıda tür argümanı tamamen farklı bir tür anlamına gelir.

Type typeToTest = typeof(Action<DateTime, float>);
bool isAction1 = typeToTest.GetGenericTypeDefinition() == typeof(Action<>);
bool isAction2 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,>);
bool isAction3 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,,>);
// isAction1 == false
// isAction2 == true
// isAction3 == false

Yana Typenesne türüne başına bir kez örneklenen, bunlar arasında referans eşitlik için kontrol edebilirsiniz. Dolayısıyla, iki nesnenin aynı genel tür tanımına sahip olup olmadığını kontrol etmek istiyorsanız, şunları yazabilirsiniz:

var listOfInts = new List<int>();
var listOfStrings = new List<string>();

bool areSameGenericType =
    listOfInts.GetType().GetGenericTypeDefinition() ==
    listOfStrings.GetType().GetGenericTypeDefinition();
// areSameGenericType == true

Bir nesnenin a yerine nullable olup olmadığını kontrol etmek Typeistiyorsanız, oldukça basit bir yöntem oluşturmak için yukarıdaki tekniği Marc Gravell'in çözümüyle birlikte kullanabilirsiniz:

static bool IsNullable<T>(T obj)
{
    if (!typeof(T).IsGenericType)
        return false;

    return typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>);
}

@ AllonGuralnek Cevabımda aşağıda basitleştirilmiş bir versiyon var. Bunu düzenleme olarak yapmak istedim ve itibarım senin seviyen olmadığından, cevabında ismim olmadan düzenlenecekti, öyle olsa bile, gözden geçirme her zaman bacağımı vuruyor gibi görünüyor, yazar olsa bile adresleme yapıyor değil. Garip dünya, bazı insanlar tanımları alamaz :).
ipavlu

@ipavlu: Versiyonunuz basitleştirilmiş değil, aslında daha karmaşık. Sanırım sonucu önbelleğe aldığınız için optimize edildiğini söylüyorsunuz. Bu anlaşılmasını zorlaştırır.
Allon Güralnek

@ AllonGuralnek statik jenerik sınıf ve statik bir kez başlatılan alanlar, bu karmaşık mı? Sevgili Tanrım, korkunç bir suç işledim :).
ipavlu

@ipavku: Evet, çünkü "Bir nesnenin boşaltılabilir olup olmadığı nasıl kontrol edilir?" sorusuyla ilgisi yoktur. Basit ve konuya girmeye çalışıyorum ve gereksiz ve ilgisiz kavramları tanıtmaktan kaçınıyorum.
Allon Güralnek

1
@nawfal: Sizi doğru anladıysam Nullable.GetUnderlyingType(), çerçeve tarafından zaten sağlanmış olanın varlığı karşısında benim uygulama arayışınız . Neden yöntemi sadece çerçevede kullanmıyorsunuz? Pekala, yapmalısın. Daha net, daha özlü ve daha iyi test edilmiştir. Ama yazımda, istediğiniz bilgiyi almak için yansımayı nasıl kullanacağımı öğretmeye çalışıyorum, böylece birisi herhangi bir türe ( typeof(Nullable<>)başka bir türle değiştirerek) uygulayabilir . GetUnderlyingType()(Orijinal veya ayrıştırılmış) kaynaklarına bakarsanız, koduma çok benzediğini göreceksiniz .
Allon Guralnek

30

Bu benim için çalışıyor ve basit görünüyor:

static bool IsNullable<T>(T obj)
{
    return default(T) == null;
}

Değer türleri için:

static bool IsNullableValueType<T>(T obj)
{
    return default(T) == null && typeof(T).BaseType != null && "ValueType".Equals(typeof(T).BaseType.Name);
}

7
Değer için, bu aynı zamanda Microsoft tarafından kullanılan
canton7

1
Güzel ... Daha sonra geldiği için bu en iyi cevap değil mi? En iyi cevabı çok kafa karıştırıcı buluyorum.
Vincent Buscarello

1
Bu en iyi cevap olmalı. Farklı yöntemleri denedikten günler sonra bu çözümü rastgele düşündüm, denedim ve mükemmel çalışıyor gibi görünüyor (en yüksek puanlı cevaba göre)
user3163495

2
Bu, herhangi bir örneğin NULL olarak ayarlanıp ayarlanamayacağını öğrenmek için mükemmel bir çözümdür, ancak sıradan nesneler de dahil olmak üzere null olarak ayarlanabilecek her şey için true değerini döndürür . Orijinal sorunun Nullable ValueTypes'i özellikle tespit etmek istediğini anlamak önemlidir.
JamesHoux

20

Şunu kullanabilirsiniz:

return !(o is ValueType);

... ama bir nesnenin kendisi null değeri yoktur veya başka türlü değildir - bir tür . Bunu nasıl kullanmayı planlıyordunuz?


2
Bu beni biraz attı. örneğin int? i = 5; typeof (i) Nullable <Int32> yerine System.Int32 döndürür - typeof (int?) Nullable <Int32> döndürür .. bu konuda netlik nereden alabilirim?
Gishu

2
typeof (i) bir derleyici hatası verir; typeof değişkeniyle kullanamazsınız. Aslında ne yaptın?
Jon Skeet

15
i.GetType () öğesi önce Object (Nesne) kutusuna gönderilir ve kutulu nullable türü diye bir şey yoktur - Nullable <int> null referansa veya kutulu int'e kutlanır.
Jon Skeet

Bu şekilde Nullable.GetUnderlyingType (type)! = Null?
Kiquenet

@Kiquenet: Biz yok olması burada tip - sadece değer.
Jon Skeet

11

Anlayabileceğim en basit yol:

public bool IsNullable(object obj)
{
    Type t = obj.GetType();
    return t.IsGenericType 
        && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}

+1. Kutulu sıfırlanabilir tipler için mükemmel çözüm. Bunu henüz özel olarak test etmedim. Yani başka biri doğrulayabilirse, takdir edilecektir.
TamusJRoyce

Zaten test ettim. Bir tür Nullableyazı yaratmalıydım, ama farklı anlambilimle Benim durumumda nullgeçerli bir değer olarak desteklemeli ve hiçbir değeri desteklememeliyim. Yani bir tür yarattı Optional. nullDeğerleri desteklemek gerektiğinden , uygulamamın bir Nullableparçası olarak değerleri işlemek için kod da uygulamak zorunda kaldım . Bu kodun geldiği yer burası.
CARLOS LOTH

9
Bence bu çözüm yanlış. Nullable değer türünün, tür nesnesinin bir parametresini bekleyen bir yönteme bağımsız değişken olarak geçirilmesi, boksun oluşmasına neden olur. Boş değer bir değer türüdür ve boks dönüşümünün sonucu bir referans türüdür. Kutulu null yok. Bu yöntemin her zaman yanlış döndürdüğüne inanıyorum?
Mishax

1
Başka cevaplar gibi bir test var mı?
Kiquenet

5
Boks değeri nedeniyle çalışmaz. Her zaman FALSE döndürür.
N Sallanan

10

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.


8

Geldiğim en basit çözüm, Microsoft'un çözümünü ( Nasıl Yapılır: Nullable Type (C # Programlama Kılavuzu) ) bir uzantı yöntemi olarak uygulamaktır:

public static bool IsNullable(this Type type)
{
    return Nullable.GetUnderlyingType(type) != null;
}

Bu daha sonra şu şekilde adlandırılabilir:

bool isNullable = typeof(int).IsNullable();

Bu aynı zamanda erişimin mantıklı bir yolu gibi görünüyor IsNullable()çünkü sınıfın diğer tüm IsXxxx()yöntemlerine uyuyor Type.


1
"! =" Yerine "==" kullanmak istemediniz mi?
vkelman

Good spot @vkelman Bu değişikliği yapmak yerine, Microsoft'tan geçerli öneriyi kullanmak için cevabı güncelledim, çünkü bu yazdığımdan beri değişti.
sclarke81

6

Sıfırlanabilir bir türü ( Nullable<int>veya örneğin int?) Boks yaparken dikkatli olun :

int? nullValue = null;
object boxedNullValue = (object)nullValue;
Debug.Assert(boxedNullValue == null);

int? value = 10;
object boxedValue = (object)value;
Debug.Assert( boxedValue.GetType() == typeof(int))

Gerçek bir referans türü haline gelir, bu yüzden boş bırakılabilir olduğu gerçeğini kaybedersiniz.


3

Belki biraz konu dışı, ama yine de bazı ilginç bilgiler. Nullable.GetUnderlyingType() != nullBir tür geçersiz kılınabiliyorsa kimliğe kullanan birçok insan buluyorum . Bu açıkça işe yarıyor, ancak Microsoft aşağıdakileri önermektedir type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)(bkz. Http://msdn.microsoft.com/en-us/library/ms366789.aspx ).

Buna performans açısından baktım. Aşağıdaki testin sonucu (bir milyon deneme), bir tür boş değerli olduğunda, Microsoft seçeneğinin en iyi performansı sağlamasıdır.

Nullable.GetUnderlyingType (): 1335ms (3 kat daha yavaş)

GetGenericTypeDefinition () == typeof (Nullable <>): 500ms

Küçük bir zamandan bahsettiğimizi biliyorum, ama herkes milisaniye ayarlamayı seviyor :-)! Patronunuz milisaniyeyi azaltmanızı istiyorsa, bu sizin kurtarıcınız ...

/// <summary>Method for testing the performance of several options to determine if a type is     nullable</summary>
[TestMethod]
public void IdentityNullablePerformanceTest()
{
    int attempts = 1000000;

    Type nullableType = typeof(Nullable<int>);

    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();
    for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
    {
        Assert.IsTrue(Nullable.GetUnderlyingType(nullableType) != null, "Expected to be a nullable"); 
    }

    Console.WriteLine("Nullable.GetUnderlyingType(): {0} ms", stopwatch.ElapsedMilliseconds);

    stopwatch.Restart();

    for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
   {
       Assert.IsTrue(nullableType.IsGenericType && nullableType.GetGenericTypeDefinition() == typeof(Nullable<>), "Expected to be a nullable");
   }

   Console.WriteLine("GetGenericTypeDefinition() == typeof(Nullable<>): {0} ms", stopwatch.ElapsedMilliseconds);
   stopwatch.Stop();
}

1
Merhaba, muhtemelen zamanı ölçmekle ilgili bir sorun var, Assert sonuçları etkileyebilir. Assert olmadan test yaptınız mı? Ayrıca Console.WriteLine ölçülen alanın dışında olmalıdır. Performans sorunlarını ölçmeye çalışmak için +1 :).
15:19

@ipavlu Console.WriteLinegerçekten ölçülü alanın dışındadır;)
nawfal

Roel, ipavlu'nun belirttiği gibi, Assertdöngü dışında olmalıdır. İkincisi, yanlış vakaları test etmek için null olmayanlara karşı da test etmelisiniz. Benzer bir test yaptım (2 nulables ve 4 nullables) ve ~ 2 saniye GetUnderlyingTypeve ~ 1 saniye alıyorum GetGenericTypeDefinition, yani GetGenericTypeDefinitioniki kat daha hızlı (üç kez değil).
nawfal

2 nullables ve 2 nullables ile başka bir tur yaptım - bu sefer GetUnderlyingType2,5 kat daha yavaştı. Sadece nullables ile - bu sefer her ikisi de boyun ve boyun.
nawfal

Ancak daha da önemlisi, GetUnderlyingTypenullabiliteyi kontrol etmeniz ve null edilebilirse altta yatan tipte olmanız gerektiğinde yararlıdır. Bu çok kullanışlıdır ve genellikle desenleri görürsünüz Activator.CreateInstance(Nullable.GetUnderlyingType(type) ?? type). Bu gibi asyanı sıra, anahtar kelime döküm denetler bunu & dönüş sonucunu yapar. Eğer altta yatan nullable türünü geri almak istiyorsanız, o zaman bir GetGenericTypeDefinitionkontrol yapmak ve daha sonra jenerik tip almak kötü bir fikir olacaktır. Ayrıca GetUnderlyingTypeçok daha okunabilir ve unutulmaz. Ben sadece ~ 1000 kez yapıyorum sakıncası olmaz.
nawfal

0

Bu versiyon:

  • sonuçları önbelleğe almak daha hızlıdır,
  • Yöntem (T obj) gibi gereksiz değişkenler gerektirmez
  • Karmaşık değil :),
  • sadece bir kez hesaplanan alanları olan statik genel sınıf

:

public static class IsNullable<T>
{
    private static readonly Type type = typeof(T);
    private static readonly bool is_nullable = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
    public static bool Result { get { return is_nullable; } }
}

bool is_nullable = IsNullable<int?>.Result;

Bence kendinize bu statik bildirimle 'is_nullable' yazdınız. İpucu: int ile nesneler bildirilsin mi? (nesne a = (int?) 8;) ve neler olduğunu görün.
SoLaR

0

En azından PLC'de - > C = 6 ile Taşınabilir Sınıf Kütüphanesi / .NET Core'da olduğu gibi, her şey başarısız gibi göründüğüm şey şu:

Çözüm: Herhangi Tipi statik yöntemler uzatın Tve Nullable<T>ve altta yatan türüne uyan statik uzantısı yöntemi çağrılır olacak ve jenerik önceliklidir olduğu gerçeğini kullanmak Tuzatma-yöntemde.

Şunun için T:

public static partial class ObjectExtension
{
    public static bool IsNullable<T>(this T self)
    {
        return false;
    }
}

ve için Nullable<T>

public static partial class NullableExtension
{
    public static bool IsNullable<T>(this Nullable<T> self) where T : struct
    {
        return true;
    }
}

Reflection ve type.IsGenericType... kullanmak , geçerli .NET Çalışma Zamanlarımda çalışmadı. MSDN Belgeleri de yardımcı olmadı .

if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {…}

Kısmen Yansıma API'sı .NET Core'da oldukça önemli bir şekilde değiştiği için.


0

Microsoft'un önerilen sınamalarını kullananların IsGenericTypeiyi olduğunu düşünüyorum , ancak GetUnderlyingTypeMicrosoft genel kod tanımında geçmediğinizden emin olmak için ek bir test kullanıyor Nullable<>:

 public static bool IsNullableType(this Type nullableType) =>
    // instantiated generic type only                
    nullableType.IsGenericType &&
    !nullableType.IsGenericTypeDefinition &&
    Object.ReferenceEquals(nullableType.GetGenericTypeDefinition(), typeof(Nullable<>));

-1

bunu yapmanın basit bir yolu:

    public static bool IsNullable(this Type type)
    {
        if (type.IsValueType) return Activator.CreateInstance(type) == null;

        return true;
    }

bunlar benim birim testlerim ve hepsi geçti

    IsNullable_String_ShouldReturn_True
    IsNullable_Boolean_ShouldReturn_False
    IsNullable_Enum_ShouldReturn_Fasle
    IsNullable_Nullable_ShouldReturn_True
    IsNullable_Class_ShouldReturn_True
    IsNullable_Decimal_ShouldReturn_False
    IsNullable_Byte_ShouldReturn_False
    IsNullable_KeyValuePair_ShouldReturn_False

gerçek birim testleri

    [TestMethod]
    public void IsNullable_String_ShouldReturn_True()
    {
        var typ = typeof(string);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Boolean_ShouldReturn_False()
    {
        var typ = typeof(bool);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Enum_ShouldReturn_Fasle()
    {
        var typ = typeof(System.GenericUriParserOptions);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Nullable_ShouldReturn_True()
    {
        var typ = typeof(Nullable<bool>);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Class_ShouldReturn_True()
    {
        var typ = typeof(TestPerson);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Decimal_ShouldReturn_False()
    {
        var typ = typeof(decimal);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Byte_ShouldReturn_False()
    {
        var typ = typeof(byte);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_KeyValuePair_ShouldReturn_False()
    {
        var typ = typeof(KeyValuePair<string, string>);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }
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.