Geçersiz bir genel tür bağımsız değişkeni için en iyi istisna


106

Şu anda UnconstrainedMelody için numaralandırmalarla ilgili genel yöntemler içeren bazı kodlar yazıyorum .

Şimdi, sadece "bayraklar" numaralandırmalarıyla kullanılması amaçlanan bir dizi yöntem içeren statik bir sınıfım var . Bunu bir kısıtlama olarak ekleyemiyorum ... bu yüzden diğer enum türleriyle de çağrılmaları mümkün. Bu durumda bir istisna yapmak isterim ama hangisini atacağımdan emin değilim.

Bunu somutlaştırmak için, eğer böyle bir şeye sahipsem:

// Returns a value with all bits set by any values
public static T GetBitMask<T>() where T : struct, IEnumConstraint
{
    if (!IsFlags<T>()) // This method doesn't throw
    {
        throw new ???
    }
    // Normal work here
}

Fırlatılacak en iyi istisna nedir? ArgumentExceptionkulağa mantıklı geliyor, ancak bu, normal bir argüman olmaktan çok, bir şeyleri kolayca karıştırabilecek bir tip argümanı. Kendi TypeArgumentExceptionsınıfımı tanıtmalı mıyım ? Kullan InvalidOperationException? NotSupportedException? Başka herhangi bir şey?

Açıkça yapılacak doğru şey olmadıkça, bunun için kendi istisnamı yaratmamayı tercih ederim .


Bugün buna, kısıtlamalarla tanımlanamayan, kullanılan türe ek gereksinimlerin yerleştirildiği genel bir yöntem yazarken rastladım. BCL'de halihazırda bir istisna türü bulamadığım için şaşırdım. Ancak bu tam ikilem, birkaç gün önce aynı projede yalnızca Flags niteliğiyle çalışacak bir jenerik için karşılaştığım bir sorundu. Ürpertici!
Andras Zoltan

Yanıtlar:


46

NotSupportedException sesler böyle uyuyor açıkça, ancak belgeler açıkça farklı bir amaç için kullanılması gerektiğini belirtmektedir. MSDN sınıfından açıklamalar:

Temel sınıfta desteklenmeyen yöntemler vardır, bunun yerine bu yöntemlerin türetilmiş sınıflarda uygulanacağı beklentisi vardır. Türetilmiş sınıf, temel sınıftan yöntemlerin yalnızca bir alt kümesini uygulayabilir ve desteklenmeyen yöntemler için NotSupportedException oluşturabilir.

Tabii ki, NotSupportedExceptionözellikle sağduyu anlamı göz önüne alındığında, yeterince iyi olduğu açıkça belli olan bir yol var . Bunu söyledikten sonra, doğru olup olmadığından emin değilim.

Unconstrained Melody'nin amacı göz önüne alındığında ...

"T: enum" veya "T: delegate" tür kısıtlamalarının olduğu genel yöntemlerle / sınıflarla yapılabilecek çeşitli yararlı şeyler vardır - ancak maalesef bunlar C # 'da yasaklanmıştır.

Bu yardımcı program kitaplığı ildasm / ilasm kullanarak yasaklar etrafında çalışır ...

... Exceptionözel oluşturmadan önce sadece buluşmamız gereken yüksek kanıt yüküne rağmen yeni bir sıra olabilir gibi görünüyor Exceptions. Bu tür bir şey InvalidTypeParameterExceptionkütüphane genelinde faydalı olabilir (veya olmayabilir - bu kesinlikle bir uç durumdur, değil mi?).

Müşterilerin bunu BCL İstisnalarından ayırt edebilmesi gerekecek mi? Bir müşteri bunu yanlışlıkla vanilya kullanarak ne zaman arayabilir enum? Özel bir istisna sınıfı yazarken hangi faktörler dikkate alınmalıdır? Sorusunun kabul edilen cevabının sorduğu soruları nasıl cevaplarsınız ?


Aslında, Kural Sözleşmelerinin yaptığı gibi, ilk etapta yalnızca dahili bir istisna atmak neredeyse cazip geliyor ... Kimsenin yakalaması gerektiğine inanmıyorum .
Jon Skeet

Ne yazık ki boş dönemez!
Jeff Sternal

25
TypeArgumentException ile gidiyorum.
Jon Skeet

Çerçeveye istisnaların eklenmesi yüksek bir "kanıtlama yüküne" sahip olabilir, ancak özel istisnaların tanımlanması olmamalıdır. Yapılacaklar gibi InvalidOperationException"Foo zaten olduğunu şey eklemek toplama Bar sorar, bu yüzden Bar IOE atar" ve "Foo şey eklemek toplama Bar sorar, bu yüzden Bar bile Bar olsa beklemiyordum olan IOE atar Boz çağırır" çünkü iğrenç olan her ikisi de aynı istisna türünü atar; ilkini yakalamayı bekleyen kod, ikincisini beklemeyecektir. Bu söylendi ...
supercat

... Buradaki bir Çerçeve istisnası lehine olan argümanın, özel bir istisnadan daha zorlayıcı olduğunu düşünüyorum. NSE'nin genel doğası, bir nesneye genel bir tür olarak atıfta bulunulduğunda ve referans noktalarının bir yeteneği destekleyeceği belirli nesne türlerinin tümü olmasa da bazıları, yeteneği kullanmayan belirli bir tür üzerinde kullanmaya çalışmaktır. Desteklemediği için NSE atması gerekir. Ben ele alacak Foo<T>bir "genel tip" olmak ve Foo<Bar>aralarında hiçbir "miras" ilişkisi var olsa bile, bu bağlamda bir "belirli tip" olmak.
supercat

25

NotSupportedException'dan kaçınırdım. Bu istisna, bir yöntemin uygulanmadığı çerçevede kullanılır ve bu tür işlemin desteklenmediğini belirten bir özellik vardır. Buraya sığmıyor

Bence InvalidOperationException buraya atabileceğiniz en uygun istisna.


NSE ile ilgili uyarı için teşekkürler. Would ... Btw de meslektaşlarınızla girdi hoşgeldin
Jon Skeet

Asıl nokta, Jon'un ihtiyaç duyduğu işlevselliğin BCL'de benzer hiçbir şeye sahip olmamasıdır. Derleyicinin onu yakalaması gerekiyor. NotSupportedException'dan "özellik" gereksinimini kaldırırsanız, bahsettiğiniz şeyler (ReadOnly koleksiyonu gibi) Jon'un sorununa en yakın şeydir.
Mehrdad Afshari

Bir nokta - bir IsFlags yöntemim var (jenerik olması gereken bir yöntem olmalı) , bu tür bir işlemin desteklenmediğini gösteren bir nevi ... bu anlamda NSE uygun olacaktır. yani arayan ilk önce kontrol edebilir .
Jon Skeet

@Jon: Bence böyle bir mülkünüz olmasa bile, ancak türünüzün tüm üyeleri doğası gereği süslenmiş Tolduğu gerçeğine güveniyor, NSE atmak geçerli olacaktır. enumFlags
Mehrdad Afshari

1
@Jon: StupidClrExceptioneğlenceli bir isim yapar;)
Mehrdad Afshari

13

Geçersiz tür parametreleri için genel programlama çalışma zamanında atılmamalıdır. Derlenmemeli, derleme zamanı yaptırımına sahip olmalısınız. Neyi IsFlag<T>()içerdiğini bilmiyorum , ama belki bunu bir derleme zamanı yaptırımına dönüştürebilirsiniz, örneğin sadece 'bayraklar' ile yaratılması mümkün olan bir tür yaratmaya çalışmak gibi. Belki bir traitssınıf yardımcı olabilir.

Güncelleme

Eğer varsa gerekir atmak, ben ınvalidoperationexception oy verirdim. Gerekçe , genel türlerin parametrelere sahip olması ve (yöntem) parametreleriyle ilgili hataların ArgumentException hiyerarşisi etrafında ortalanmasıdır. Ancak, ArgumentException ile ilgili öneri şunu belirtir:

başarısızlık bağımsız değişkenleri içermiyorsa, InvalidOperationException kullanılmalıdır.

Burada en az bir inanç sıçraması var, yöntem parametreleri önerileri genel parametrelere de uygulanacak , ancak SystemException hierachy imho'da daha iyi bir şey yok.


1
Hayır, bunun derleme zamanında sınırlandırılmasının bir yolu yok. IsFlag<T>numaralandırmanın [FlagsAttribute]uygulanıp uygulanmadığını belirler ve CLR özniteliklere dayalı kısıtlamalara sahip değildir. Mükemmel bir dünyada olurdu - ya da onu sınırlamanın başka bir yolu olurdu - ama bu durumda işe yaramaz :(
Jon Skeet

(Gerçi genel ilkesine 1 - Ben olmak isterdim mümkün . Zorlaması)
Jon Skeet

9

NotSupportedException'ı söylediğiniz gibi kullanırdım. Belirli olanlar dışındaki diğer numaralandırmalar desteklenmez . Bu, elbette istisna mesajında ​​daha açık bir şekilde ifade edilecektir.


2
NotSupportedException, BCL'de çok farklı bir amaç için kullanılır. Buraya uymuyor. blogs.msdn.com/jaredpar/archive/2008/12/12/…
JaredPar

8

Ben giderdim NotSupportedException. İyi görünse de ArgumentException, bir yönteme iletilen bir argümanın kabul edilemez olması gerçekten beklenir. Bir tür bağımsız değişkeni, gerçek bir "bağımsız değişken" değil, çağırmak istediğiniz gerçek yöntem için tanımlayıcı bir özelliktir. InvalidOperationExceptionGerçekleştirdiğiniz işlem bazı durumlarda geçerli olduğunda atılmalıdır, ancak belirli bir durum için kabul edilemez.

NotSupportedExceptionbir işlem doğası gereği desteklenmediğinde atılır. Örneğin, belirli bir üyenin bir sınıf için anlamlı olmadığı bir arabirim uygularken. Bu benzer bir duruma benziyor.


Mmm. Hala gelmez oldukça doğru hissediyorum, ama buna yakın şey olacak düşünüyorum.
Jon Skeet

Jon: Bu doğru gelmiyor çünkü doğal olarak derleyici tarafından yakalanmasını bekliyoruz.
Mehrdad Afshari

Evet. Bu, uygulanmasını istediğim ama yapamadığım tuhaf bir kısıtlama :)
Jon Skeet

6

Görünüşe göre, Microsoft, kullandığı ArgumentExceptionörneği üzerinde gösterildiği gibi, bunun için Expression.Lambda <> , Enum.TryParse <> veya Marshal.GetDelegateForFunctionPointer <> İstisnalar bölümünde. Ben de aksini gösteren herhangi bir örnek bulamadım ( TDelegateve için yerel referans kaynağı aramasına rağmen TEnum).

Bu nedenle, en azından Microsoft kodunda ArgumentException, temel değişkenler dışında geçersiz genel tür bağımsız değişkenler için kullanılmasının yaygın bir uygulama olduğunu varsaymanın güvenli olduğunu düşünüyorum . Dokümanlardaki istisna tanımının bunlar arasında ayrım yapmadığı göz önüne alındığında , bu da çok fazla bir zorunluluk değildir.

Umarım soruya kesin olarak karar verir.


Çerçevesinde tek bir örnek yok, benim için yeterli değil - MS diğer durumlarda kötü bir seçim yapmış :) Ben türetmek değil diye düşünüyorum yerlerin sayısı göz önüne alındığında TypeArgumentExceptiongelen ArgumentExceptionbir tür argümanı düzenli değildir çünkü, argüman.
Jon Skeet

1
Bu, "MS'in tutarlı bir şekilde yaptığı şey" açısından kesinlikle daha zorlayıcı. Belgeleri eşleştirme açısından daha zorlayıcı hale getirmiyor ... ve C # ekibinde normal argümanlar ile tip argümanları arasındaki farkı derinden önemseyen pek çok insan olduğunu biliyorum :) Ama örnekler için teşekkürler - çok faydalıdırlar.
Jon Skeet

@Jon Skeet: Bir düzenleme yaptı; şimdi, hepsi ArgumentException atılmış olarak belgelenen farklı MS kitaplıklarından 3 örnek içerir; yani kötü bir seçimse, en azından tutarlı, kötü bir seçimdir. ;) Sanırım Microsoft, normal bağımsız değişkenlerin ve tür bağımsız değişkenlerinin her ikisinin de bağımsız değişken olduğunu varsayar; ve şahsen, böyle bir varsayımın oldukça makul olduğunu düşünüyorum. ^^ '
Alice

Ah, boşver, bunu zaten fark etmişsin. Yardımcı olduğuma sevindim. ^^
Alice

Sanırım onlara aynı şekilde davranmanın makul olup olmadığı konusunda hemfikir olmamız gerekecek. Düşünme, dil kuralları vb. Söz konusu olduğunda kesinlikle aynı değillerdir ... çok farklı ele alınırlar .
Jon Skeet


2

Özel yapılmış bir istisna, şüpheli olduğu her durumda her zaman yapılmalıdır. Özel bir istisna, API kullanıcılarının ihtiyaçları ne olursa olsun her zaman işe yarar. Geliştirici umursamazsa herhangi bir istisna türünü yakalayabilir, ancak geliştiricinin özel bir işleme ihtiyacı varsa, SOL olacaktır.


Ayrıca geliştirici, XML yorumlarında atılan tüm istisnaları belgelemelidir.
Eric Schneider

1

NotSupportedException'dan devralmaya ne dersiniz? @Mehrdad ile en mantıklı olduğu konusunda hemfikir olsam da, tam olarak uymadığını duyduğunuzu duydum. Bu nedenle, NotSupportedException'dan devralın ve bu şekilde API'nize karşı kodlama yapan kişiler bir NotSupportedException'ı yakalayabilir.


1

Tamamen her zaman açıkça belgelenmedikleri ve doğru adlandırılmadıkları takdirde kafa karışıklığına neden oldukları gerekçesiyle özel istisnalar yazmaktan her zaman çekinirim.

Bu durumda, bayrak kontrolü başarısızlığı için bir ArgumentException oluştururum. Her şey gerçekten tercihe bağlı. Gördüğüm bazı kodlama standartları, bunun gibi senaryolarda hangi tür istisnaların atılması gerektiğini tanımlayacak kadar ileri gider.

Kullanıcı bir numaralandırma olmayan bir şeyi geçirmeye çalışıyorsa, bir InvalidOperationException atardım.

Düzenle:

Diğerleri bunun desteklenmediği konusunda ilginç bir noktaya işaret ediyor. NotSupportedException ile ilgili tek endişem, genellikle sisteme "karanlık madde" eklendiğinde ortaya çıkan istisnalar veya başka bir deyişle, "Bu yöntem bu arayüzde sisteme girmeli, ancak kazandık "2.4" sürümüne kadar açmayın "

NotSupportedExceptions'ın bir lisans istisnası olarak atıldığını da gördüm "bu yazılımın ücretsiz sürümünü çalıştırıyorsunuz, bu işlev desteklenmiyor".

Düzenleme 2:

Bir başka olası:

System.ComponentModel.InvalidEnumArgumentException  

Numaralandırıcı olan geçersiz bağımsız değişkenler kullanılırken atılan istisna.


Onu bir numaralandırma olarak sınırlandıracağım (biraz jiggery pokery'den sonra) - sadece endişelendiğim bayraklar.
Jon Skeet

Bence bu lisans veren kişiler, LicensingExceptionmiras alan bir sınıfın bir örneğini atmalılar InvalidOperationException.
Mehrdad Afshari

Mehrdad'a katılıyorum, İstisnalar maalesef çerçevede çok fazla gri olan alanlardan biri. Ama eminim ki bu birçok dil için aynıdır. (vb6'nın çalışma zamanı hatası 13 hehe'ye geri döneceğimi söylemiyor)
Peter

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.