Nasıl C # genel bir istisna tüm varyantları yakalamak için


22

Genel bir istisna sınıfının tüm çeşitlerini yakalamak istiyorum ve bunu birden fazla catch bloğu olmadan yapmanın bir yolu olup olmadığını merak ediyordum. Örneğin, bir istisna sınıfım olduğunu varsayalım:

public class MyException<T> : Exception
{
    public string MyProperty { get; }

    public MyException(T prop) : base(prop.ToString())
    {
        MyProperty = prop?.ToString();
    }
}

ve iki türetilmiş sınıf:

public class MyDerivedStringException : MyException<string>
{
    public MyDerivedStringException(string prop) : base(prop)
    {

    }
}

public class MyDerivedIntException : MyException<int>
{
    public MyDerivedIntException(int prop) : base(prop)
    {

    }
}

Her iki alıcı bir yolu yoktur MyDerivedStringExceptionve MyDerivedIntExceptionbir catch bloğunda.

Bunu denedim:

try
{
   ...
}

catch(Exception e) when (e is MyDerivedStringException || e is MyDerivedIntException)
{
}

ama çok temiz değil ve erişimim olmadığı anlamına geliyor MyProperty.

Soruna genel bir çözümle ilgileniyorum, ancak benim durumumda, genel İstisna, aşağıda belirtildiği gibi, soruna bazı ek kısıtlamalar ekleyen bir üçüncü taraf kütüphanesinde tanımlanmıştır.

Yanıtlar:


15

Yap MyException<T>bir arabirim uygulamak ve arayüz türüne göre bir istisna olmadığını kontrol edin.

Arayüz:

public interface IMyException
{
    string MyProperty { get; }
}

Arabirimi uygulayan genel sınıf:

public class MyException<T> : Exception, IMyException
{
    public string MyProperty { get; }

    public MyException(T prop)
    {
        MyProperty = prop?.ToString();
    }
}

Türetilmiş sınıflar:

public class MyDerivedStringException : MyException<string>
{
    public MyDerivedStringException(string prop) : base(prop)
    {

    }
}

public class MyDerivedIntException : MyException<int>
{
    public MyDerivedIntException(int prop) : base(prop)
    {

    }
}

Kullanımı:

try
{
    // ...
}
catch (Exception e) when (e is IMyException)
{
    // ...
}

Aynı şey, bu temel sınıftan miras alınan Exceptionve ondan MyException<T>türetmek yerine bir temel sınıf oluşturarak da yapılabilir .


3
Burada bir arayüze değdiğinden emin değilim - sadece jenerik olmayan bir temel sınıf arasında Exceptionve iyi MyException<T>olurdu.
Jon Skeet

Ayrıca, OP hala asıl sorun olduğunu tahmin genel özelliği (yansıma kullanmadan) erişimi yok.
DavidG

10

TypeBir jenerikten türetilmiş ise test şudur:

Type = typeof(something);
t.GetGenericTypeDefinition()==typeof(MyException<>);

Ancak bu yalnızca türetilmiş türlerin kendisi için geçerlidir, MyException<int>veya gibi MyException<string>.

MyDerivedStringExceptionTest etmek zorunda olduğunuz başka türevleriniz varsa:

ex.GetType.BaseType.GetGenericTypeDefinition()==typeof(MyException<>);

Bu, mevcut herhangi bir jenerik için işe yarar, ancak bu test için kalıtım seviyesini bilmeniz veya tüm temel türlerde dolaşmanız gerekir.

Böylece bunu yapabilirsiniz:

catch(Exception ex) when (ex.GetType.BaseType.GetGenericTypeDefinition()==typeof(MyException<>))

3

T: Değer Valuetype ise bu uygulama kutuları ve kutularını kaldırır ... ancak kullanımla ilgili olarak, performans sonuçlarını kutu / kutu açma girişiminizle kontrol edebilirsiniz.

public class MyException<T> : MyException
{
    public T Prop => (T)base.Prop;

    public MyException(T prop) : base(prop)
    {

    }
}

public class MyException : Exception
{
    protected object Prop { get; }

    public MyException(object prop)
    {
         Prop = prop;
    }
}

Mantık

try {
     ...
} catch(MyException e) {
    ...
}

Bu iyi bir yanıt ve kaldırdım - maalesef genel istisna bir üçüncü taraf kütüphanesinde olduğu için özel sorunumu çözmüyor, bu yüzden düzenleyemiyorum.
SBFrancies

2

Ne yazık ki,

catch(MyException ex) bir sınıf beklediği için.

En iyi seçeneğiniz bir temel sınıf veya arayüz oluşturmak, onu yakalamak ve oradan türü almak olacaktır.

Zaten burada bir tür almak ve bunu yapmak için bir cevap var .


1

Bu uygulama, istisna türü için yönetim temsilcisini T / C bağlamından soyutlar ... Bu biraz fazla maceracı olabilir, ancak bunun serin kısmı, yeniden kullanım kapsamına ve içeriğine bağlı olarak farklı işleyiciler enjekte edebilirsiniz. kullanım.

public interface IExceptionHandler
{
    object Handle(Exception ex);

    void RegisterExceptionTypeHandler<T>(Func<T,object> handlerDelegate) where T : Exception;
}

kayıt mantığı

handler.RegisterExceptionTypeHandler<MyException<int>>(ex => ...);
handler.RegisterExceptionTypeHandler<MyException<string>>(ex => ...);

try {
    ...
}catch(Exception ex)
{
    ...any validation
    return exceptionHandler.Handle(ex)
}
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.