Nasıl C # genel bir yöntemden NULL dönebilirim?


546

Bu (kukla) kodu ile genel bir yöntem var (evet IList tahmin ediyor, ama benim kod IList ama başka bir koleksiyon kullanmıyor, yine de bu soru için alakasız olduğunu biliyorum ...)

static T FindThing<T>(IList collection, int id) where T : IThing, new()
{
    foreach T thing in collecion
    {
        if (thing.Id == id)
            return thing;
    }
    return null;  // ERROR: Cannot convert null to type parameter 'T' because it could be a value type. Consider using 'default(T)' instead.
}

Bu bana bir yapı hatası veriyor

Msgstr "Bir değer türü olabileceğinden null türünü 'T' türüne dönüştüremezsiniz. Bunun yerine 'default (T)' kullanmayı düşünün."

Bu hatayı önleyebilir miyim?


Null edilebilir referans türleri (C # 8'de) şimdi bunun için daha iyi bir çözüm olabilir mi? docs.microsoft.com/en-us/dotnet/csharp/nullable-references dönen nullbakılmaksızın ait Tolduğu Objectveya intya char.
Alexander - Monica'yı eski haline getirin

Yanıtlar:


968

İki seçenek:

  • İade default(T)iade demektir nullT referans tipi (veya bir null değer türü) ise, 0için int, '\0'için char, vb ( varsayılan değerler tablo (C # Reference) )
  • T'yi where T : classkısıtlamayla birlikte bir referans türü olarak kısıtlayın ve sonra nullnormal şekilde geri dönün

3
Dönüş türüm bir sınıf değil bir enum ise ne olur? T: enum :(
Justin

1
.NET'te bir enum, tamsayı tipi etrafında çok ince (ve oldukça sızdıran) bir paketleyicidir. Kural "varsayılan" numaralandırma değeriniz için sıfır kullanmaktır.
Mike Chamberlain

27
Ben bu sorunu söylemek için bu genel yöntemi kullanıyorsanız, DbNull Int bir veritabanı nesnesi dönüştürmek ve T (bir int olduğu varsayılan (T) döndürür, 0 döndürür olduğunu düşünüyorum. aslında anlamlıysa, bu alanın boş olduğu durumlarda kötü verilerden geçiyor olursunuz. Veya daha iyi bir örnek DateTime olabilir. Alan "DateClosed" gibi bir şeye sahipse ve hesap hala açık olduğu için null olarak döndürülmüşse, gerçekte varsayılan olarak (DateTime) 1/1/0000 olur ve hesabın bilgisayarlar icat edilmeden önce kapatıldığını gösterir.
Sinaesthetic

21
@Sinaesthetic: Demek Nullable<int>ya da Nullable<DateTime>onun yerine dönüşürsünüz Null edilemeyen bir tür kullanıyorsanız ve null bir değeri temsil etmeniz gerekiyorsa, yalnızca sorun istiyorsunuz demektir.
Jon Skeet

1
Katılıyorum, sadece büyütmek istedim. Sanırım yaptığım şey MyMethod <T> (); nullable olmayan bir tür olduğunu ve MyMethod <T?> (); null olabilecek bir tür olduğunu varsaymak. Yani senaryolarımda, bir null yakalamak ve oradan gitmek için geçici bir değişken kullanabilirdim.
Sinaestetik

84
return default(T);

Bu bağlantı: msdn.microsoft.com/en-us/library/xwth0h0d(VS.80).aspx nedenini açıklamalıdır.
Harper Shelby

1
Kahretsin, bu anahtar kelimeyi bilseydim çok zaman kazanırdım - teşekkürler Ricardo!
Ana Betts

1
'Varsayılan' anahtar kelime daha kapsamlı bir çözüm olduğundan, daha fazla oy almamış olmasına şaşırıyorum, referans olmayan türlerin sayısal türler ve yapılarla birlikte kullanılmasına izin veriyor. Kabul edilen cevap sorunu çözse de (ve gerçekten de faydalıdır), dönüş türünün boş / referans türleriyle nasıl sınırlandırılacağı daha iyi yanıtlar verir.
Steve Jackson

33

Kısıtlamalarınızı ayarlayabilirsiniz:

where T : class

Sonra null döndürmeye izin verilir.


Teşekkürler. Kabul edilen çözüm olarak 2 cevap seçemiyorum, bu yüzden John Skeet'i seçiyorum çünkü cevabının iki çözümü var.
edosoft

@Migol gereksinimlerinize bağlıdır. Belki de projeleri öyle olmasını gerektirir IDisposable. Evet, çoğu zaman olmak zorunda değildir. Örneğin, System.Stringuygulamaz IDisposable. Cevaplayıcı bunu açıklığa kavuşturmuş olmalıydı, ancak bu yanıtı yanlış yapmaz. :)
ahwm

@Migol Neden orada düşünülemez olduğum hakkında hiçbir fikrim yok. Kaldırıldı.
TheSoftwareJedi

13

Sınıf kısıtlamasını genel türünüzün ilk kısıtlaması olarak ekleyin.

static T FindThing<T>(IList collection, int id) where T : class, IThing, new()

Teşekkürler. Kabul edilen çözüm olarak 2 cevap seçemiyorum, bu yüzden John Skeet'i seçiyorum çünkü cevabının iki çözümü var.
edosoft

7
  1. Nesneniz varsa o zaman tahmin etmeniz gerekir

    return (T)(object)(employee);
  2. null döndürmeniz gerekiyorsa.

    return default(T);

Merhaba user725388, lütfen ilk seçeneği doğrulayın
Jogi Joseph George

7

Kullanabileceğiniz iki seçenek aşağıdadır

return default(T);

veya

where T : class, IThing
 return null;

6

Diğer seçeneğiniz bunu beyanınızın sonuna eklemek olacaktır:

    where T : class
    where T: IList

Bu şekilde null değerini döndürmenize izin verir.


Her iki kısıtlama da aynı türdeyse, türden bir kez bahseder ve virgül kullanırsınız where T : class, IList. Farklı türler için kısıtlamalarınız varsa jetonu whereolduğu gibi tekrarlayın where TFoo : class where TBar : IList.
Jeppe Stig Nielsen

3

TheSoftwareJedi çalışmalarının çözümü,

ayrıca değeri ve null türlerini çift kullanarak arşivleyebilirsiniz:

static T? FindThing<T>(IList collection, int id) where T : struct, IThing
{
    foreach T thing in collecion
    {
        if (thing.Id == id)
            return thing;
    }
    return null;
}

1

Hatanın önerisini alın ... ya da kullanıcı default(T)veya new T.

Bu rotaya giderseniz geçerli bir eşleşme olduğundan emin olmak için kodunuza bir karşılaştırma eklemeniz gerekir.

Aksi takdirde, "eşleşme bulundu" için potansiyel olarak bir çıkış parametresi düşünün.


1

İşte Nullable Enum dönüş değerleri için çalışan bir örnek:

public static TEnum? ParseOptional<TEnum>(this string value) where TEnum : struct
{
    return value == null ? (TEnum?)null : (TEnum) Enum.Parse(typeof(TEnum), value);
}

C # 7.3'ten (Mayıs 2018) beri, kısıtlamayı geliştirebilirsiniz where TEnum : struct, Enum. Bu, arayanın yanlışlıkla enum olmayan bir değer türü ( inta veya a gibi DateTime) sağlamamasını sağlar .
Jeppe Stig Nielsen

0

Yukarıda sunulan 2 cevaba başka bir alternatif. Eğer dönüş türü için değiştirirseniz object, sen dönebilirsiniz nullaynı anda boş olmayan dönüşünü yayınlarken bir yandan.

static object FindThing<T>(IList collection, int id)
{
    foreach T thing in collecion
    {
        if (thing.Id == id)
            return (T) thing;
    }
    return null;  // allowed now
}

Dezavantajı: bu, arayan kişinin döndürülen nesneyi (boş olmayan durumda) yayınlaması için yöntemin arayanını gerektirir, bu da boks -> daha az performans anlamına gelir. Haklı mıyım?
Csharpest

0

Tamlık uğruna, bunu da yapabileceğinizi bilmek güzel:

return default;

Aynı döndürür return default(T);


0

Benim için olduğu gibi çalışıyor. Sorun tam olarak nerede?

public static T FindThing<T>(this IList collection, int id) where T : IThing, new()
{
    foreach (T thing in collection)
    {
        if (thing.Id == id)
            return thing;
        }
    }

    return null; //work
    return (T)null; //work
    return null as T; //work
    return default(T); //work


}
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.