How to perform a switch statement on a generic type in C#?
Asked Answered
R

2

7

I'm having some troubles to check the proper type on a switch statement. I have these classes that extends from Exception

public abstract class DomainException<T>: Exception
{
    public readonly DomainExceptionCodes Code;
    public readonly T Metadata;

    public DomainException(DomainExceptionCodes code, T metadata): base(message: code.GetEnumDescription())
    {
        Code = code;
        Metadata = metadata;
    }
}

public class EmptyFieldsException : DomainException<EmptyFieldsMetadata>
{
    public EmptyFieldsException(EmptyFieldsMetadata metadata) : base(code: DomainExceptionCodes.EmptyField, metadata)
    {
    }
}

Let's asume there is a bunch of derived classes. What I need to do, is to be able to manage all of the derived clases in the same way when handling the exception.

Something like:

try{
    // code that raise the exception
}
catch (Exception e) {
   // some code here
   switch(e) {
       case DomainException:
            // do something
            break;
       default:
            //other code here
            break;
   }
}

However, because DomainException requires at least one argument for the generic type it's raising an error

enter image description here

I tried with object and dynamic, but then the type does not match

enter image description here

Any clues?

Rento answered 6/9, 2022 at 6:11 Comment(1)
It's the same problem catch (DomainException e) will require an argument for the generic type, and dynamic and object won't match. I don't want to have a catch or a case for every derived class. I want to use the base classRento
V
8

Unfortunately for your problem, that's not how generics work in .NET. The generic type argument is not erased, so A<T> is not A<object> (which would of course violate type safety!).

If you can change the definition of DomainException<T>, the best solution would be to add an intermediate non-generic type:

class DomainException: Exception
{
  public readonly DomainExceptionCodes Code;
}

class DomainException<T>: DomainException
{
  public T Metadata;
}

Then you can just catch the non-generic exception to get the code, and only need the generic variant to access the metadata (which presumably means you already know what type to expect there).

If you can't change the exception definition, unfortunately your only recourse is to use reflection. Something like this should work:

try
{
  ...
}
catch (Exception ex) 
  when (
        ex.GetType().IsGenericType 
        && ex.GetType().GetGenericTypeDefinition() == typeof(DomainException<>)
      )
{
  ...
}

Unfortunately, in this case even to access the code, you'll need to use reflection.

Vomitory answered 6/9, 2022 at 6:24 Comment(0)
D
1

as mentioned by this SO question, you can't rally catch all types at once. The code below (taken from the other question) should do what you need.

// ...

catch (FaultException ex)
{
    Type exceptionType = ex.GetType();

    if (exceptionType.IsGenericType)
    {
        // Find the type of the generic parameter
        Type genericType = ex.GetType().GetGenericArguments().FirstOrDefault();

        if (genericType != null)
        {
            // TODO: Handle the generic type.
        }
    }
}
Doggish answered 6/9, 2022 at 6:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.