Despertar
Despertar

Reputation: 22362

Can you catch a Exception<T> Where T is any type?

I want to be able to catch a WebFaultException<string> as the most specific then a WebFaultException<T> (T being any other type) as a more general case to handle. Is this possible?

try
{
    // throw exception
}
catch (WebFaultException<string> e)
{
    // handle more specific type
}
catch (WebFaultException<T> e)
{
    // handle more general type
}
catch (Exception e)
{
}

Upvotes: 43

Views: 16394

Answers (8)

Dave Cousineau
Dave Cousineau

Reputation: 13148

Use a non-generic base class. It's very often good practice anyway to have a non-generic base. You can push all non-generic data and functionality up into it as well, solving the problem of having lists of varied generic type.

Rather than (applies whether inheriting from Exception or not):

sealed class MyClass<T> {
   public T GenericProperty { get; set; }
   public int NonGenericProperty { get; set; }
}

Do this:

// optionally abstract
class MyClass {
   public int NonGenericProperty { get; set; } 
}

sealed class MyClass<T> : MyClass {
   public T GenericProperty { get; set; }
}

Upvotes: 0

Jay
Jay

Reputation: 3355

I personally abstract creation of exceptions to a generic class which is derived from Exception.

https://net7mma.codeplex.com/SourceControl/latest#Common/Exception.cs

I have also defined an Interface IExceptionEx to accommodate the derivation.

This gives you the opportunity to wrap exceptions like so...

try{ /*error prone logic*/ } catch (Exception ex) { Common.ExceptionExtensions.CreateAndRaiseException(this, "Could not resolve host from the given location. See InnerException.", ex); }

Catching specific types then works like this...

catch (Common.Exception<RtspClient>) { throw; } catch (Common.Exception<SessionDescription>) { Common.ExceptionExtensions.CreateAndRaiseException(this, "Unable to describe media, Session Description Exception Occured."); }

You can catch all derived with this:

catch (Common.Exception common) {}

Or every Exception with this

catch (Exception ex) {}

Upvotes: 0

supercat
supercat

Reputation: 81105

A few points not yet mentioned:

  1. If one could catch interfaces, it would be possible for a `Catch IFooException` statement to catch a `IFooException`, but since one can only catch class types derived from Exception, and since class types do not support covariance, there are limits to how well one can use the concept of inheritance with generic exceptions. The closest one can come is to have `FooException` derive from `FooException`. That might not be a bad idea, but would be a little clunky.
  2. If one catches `SomeException Ex` and passes `Ex` to a factory method `MakeGenericException(T Ex) where T:Exception`, which is supposed to produce an instance of `FooException`, the resulting exception will always be of type `FooException` even if the caught exception was actually a derivative of `SomeException`. Given the lack of covariant generic exception types, this is probably a good thing (since a `FooException` could not be caught be code expecting to catch a `FooException`) but it's still worth noting.

Using generic type parameters with exceptions seems like a nice ability, especially given that one set of constructors can be used for a whole family of exceptions. Unfortunately, it doesn't seem to work nearly as well as one would hope.

Upvotes: 2

perfectionist
perfectionist

Reputation: 4346

You can manage something similar by deriving your exception class from a common base

public class WebFaultException<T> : WebFaultException
{
    public WebFaultException(T content) : base(content)
    public T Content { get { return ObjContent; } }
}

public class WebFaultException
{
    public WebFaultException(object content)
    {
        ObjContent = content;
    }

    public object ObjContent { get; private set; }
}

now you can catch WebFaultException, or WebFaultException<string>

Upvotes: 1

Samuel Slade
Samuel Slade

Reputation: 8613

As other answers have mentioned; you cannot directly specify to catch every WebFaultException<T> without either knowing the specified type argument, or catching it's base type instead.

However, if you were wanting to catch all WebFaultException occurrences and handle the response differently based on what the generic type is, then you could simply catch the base type and use reflection to determine the type of the generic argument using Type.GetGenericArguments(). Here is a simple catch clause to show how you may go about doing it:

// ...

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

If you want a more indepth example, I have uploaded a test program to demonstrate this to PasteBin. Feel free to take a look!

Upvotes: 17

GazTheDestroyer
GazTheDestroyer

Reputation: 21241

A generic type is a type in itself, there is no concept of the templated parameter at runtime, so WebFaultException is in no way related to WebFaultException.

If I were you I would create a non generic WebFaultException base, and derive your generic types from that.

Upvotes: 1

bitbonk
bitbonk

Reputation: 49609

Unfortunately this is not possible. You can use WebFaultException's common nongeneric base class and then catch that and handle or rethrow the more specifc exceptions using reflection in that handler.

I'd recommend to not depend on generic type arguments in exception handling. Generics will always get in your way whenever you have to make decisions based on a type.

Upvotes: 3

Erik Dietrich
Erik Dietrich

Reputation: 6090

I've never thought of anything like this, so I got curious and did a little scratch pad implementation. First off, the following works:

public class WebFaultException : Exception
{
    public WebFaultException() { }
    public WebFaultException(string message) : base(message) { }
    public WebFaultException(string message, Exception innerException) : base(message, innerException) { }
    protected WebFaultException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}

public class WebFaultException<T> : WebFaultException
{
    public WebFaultException() { }
    public WebFaultException(string message) : base(message) { }
    public WebFaultException(string message, Exception innerException) : base(message, innerException) {  }
    protected WebFaultException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) {}
}

As your exception definitions and then these tests both pass:

    [TestMethod]
    public void SpecificGeneric()
    {
        bool hitException = false;
        try
        {
            throw new WebFaultException<string>();
        }
        catch(WebFaultException<string> e)
        {
            hitException = true;
        }

        Assert.IsTrue(hitException);
    }

    [TestMethod]
    public void AnyGeneric()
    {
        bool hitException = false;
        try
        {
            throw new WebFaultException<int>();
        }
        catch (WebFaultException<string> e)
        {
            hitException = false;
        }
        catch (WebFaultException e)
        {
            hitException = true;
        }

        Assert.IsTrue(hitException);
    }

In terms of doing what you want specifically, there's a catch. In the code as you presented it, WebDefaultException<T> is meaningless because you have provided no T. However, you can get around that (somewhat awkwardly) like this (another passing unit test):

    [TestMethod]
    public void CallingGenericMethod()
    {
        Assert.IsTrue(GenericExceptionMethod<int>());
    }

    private bool GenericExceptionMethod<T>()
    {
        bool hitException = false;
        try
        {
            throw new WebFaultException<int>();
        }
        catch (WebFaultException<string> e)
        {
            hitException = false;
        }
        catch (WebFaultException<T> e)
        {
            hitException = true;
        }
        return hitException;
    }

That is, if the method (or class) in which you're handling the exception has a generic parameter, you can actually catch WebFaultException<T>. However, I would urge a word of caution that this is a very weird thing to do -- as a client of your method, I'm forced to pass in a type that will be used for nothing that I care about and is an internal implementation detail to you for some exception that you want to catch.

So, I'd say yes, possible. But also awkward at best and perhaps ill-advised.

Upvotes: 5

Related Questions