C #에서 일반 예외의 모든 변형을 잡는 방법


22

일반 예외 클래스의 모든 변형을 잡고 싶습니다. 여러 catch 블록없이 수행 할 수있는 방법이 있는지 궁금합니다. 예를 들어 예외 클래스가 있다고 가정 해보십시오.

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

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

그리고 2 개의 파생 클래스 :

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

    }
}

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

    }
}

모두 잡는 방법이있다 MyDerivedStringExceptionMyDerivedIntException하나 개의 catch 블록은.

나는 이것을 시도했다 :

try
{
   ...
}

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

그러나 그것은 매우 깨끗하지 않으며 내가 액세스 할 수 없음을 의미합니다 MyProperty.

나는 문제에 대한 일반적인 해결책에 관심이 있지만 내 경우에는 일반적인 지적 예외가 타사 라이브러리에 정의되어 있으며 아래 지적 된 것처럼 문제에 대한 추가 제약 조건이 추가되었습니다.

답변:


15

확인 MyException<T>인터페이스를 구현하고 인터페이스 유형에 의해 예외를 확인하십시오.

상호 작용:

public interface IMyException
{
    string MyProperty { get; }
}

인터페이스를 구현하는 일반 클래스 :

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

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

파생 클래스 :

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

    }
}

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

    }
}

용법:

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

동일은 기본 클래스를 생성하여 수행 할 수있는 상속에서 Exception와 만드는 것보다 MyException<T>그 기본 클래스에서 파생합니다.


3
나는 그것이 인터페이스의 가치가 있는지 확실하지 않습니다-단지 제네릭이 아닌 기본 클래스 ExceptionMyException<T>괜찮을 것입니다.
Jon Skeet

또한 OP는 여전히 실제 문제라고 생각하는 일반 속성 (반사를 사용하지 않고)에 액세스 할 수 없습니다.
DavidG

10

귀하 Type가 일반에서 파생 된 경우의 테스트 는 다음과 같습니다.

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

그러나 이것은 MyException<int>또는 같은 파생 유형 자체에만 해당됩니다 MyException<string>.

다음과 같이 추가 파생 상품이있는 경우 다음 MyDerivedStringException을 테스트해야합니다.

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

따라서 이것은 모든 일반 제네릭에 적용되지만이 테스트의 상속 수준을 알고 있거나 모든 기본 유형을 반복해야합니다.

그래서 당신은 이것을 할 수 있습니다 :

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

3

이 구현은 T : Value가 Valuetype ... 인 경우 상자를 열고 상자를 풉니 다. 그러나 사용률과 관련하여 상자 / 상자를 풀려고 시도하는 횟수로 성능 관련 사항을 제어 할 수 있습니다.

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

논리

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

이것은 좋은 대답이며 공감했습니다. 불행히도 일반적인 예외가 타사 라이브러리에 있으므로 편집 할 수 없으므로 특정 문제를 해결하지 못합니다.
SBFrancies

2

불행히도, 당신은 따라 잡을 수 없습니다

catch(MyException ex) 유형을 기대하는 클래스.

가장 좋은 방법은 기본 클래스 또는 인터페이스를 작성하고 잡아서 유형을 얻는 것입니다.

에 대한 답변 이미 있습니다 그래서 여기 유형을 얻을이 작업을 수행하는 방법은.


1

이 구현은 예외 유형에 대한 처리 대의원을 T / C의 맥락에서 멀리 추상화합니다. 이것은 다소 모험적 일 수 있지만 멋진 부분은 재사용 범위와 문맥에 따라 다른 핸들러를 주입 할 수 있다는 것입니다. 이용.

public interface IExceptionHandler
{
    object Handle(Exception ex);

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

등록 논리

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

try {
    ...
}catch(Exception ex)
{
    ...any validation
    return exceptionHandler.Handle(ex)
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.