Inconsistence! .NET 2.0 Generics and Exceptions

V

Vladimir Shiryaev

Hello!

Exception handling in generics seems to be a bit inconsistent to me.

Imagine, I have "MyOwnException" class derived from "ApplicationException".
I also have two classes "ThrowInConstructor" and "ThrowInFoo". First one
throws "MyOwnException" in constructor, second one in "Foo()" method. There
is a "GenericCatch" generics class able to accept "ThrowInConstructor" and
"ThrowInFoo" as type parameter "<T>". There are two methods in
"GenericCatch": "CatchInFoo()" and "CatchInConstructor()". Each method has a
"try{}catch(MyOwnException)" block. Object of type "T" created inside try
block and "Foo()" method is called for it.

----------
The INCONSISTENCE is:

Exception "MyOwnException" thrown from constructor of "ThrowInConstructor",
somehow TURNS INTO "TargetInvocationException" and is NOT caught by
"catch(MyOwnException)" block!!!
----------

There are four possible choices:

1. "catch" block is placed somewhere in class without generics.

1.1 Exception "MyOwnException" thrown in ordinary "Foo()" method falls into
"catch(MyOwnException)" block.
1.2 Exception "MyOwnException" thrown in constructor falls into
"catch(MyOwnException)" block.

2. "catch" block is placed somewhere in class WITH generics.

2.1 Exception "MyOwnException" thrown in ordinary "Foo()" method falls into
"catch(MyOwnException)" block.
2.2 Exception "MyOwnException" thrown in constructor turn into
"TargetInvocationException" (with "InnerException" property set to
"MyOwnException") and DOES NOT fall into "catch(MyOwnException)" block.

Any ideas WHY ??? May be I miss something ???

P.S.
You can find an example (simple C# console application) that illustrates
this issue below.

Thanks,
Vladimir

//
// .NET Framework 2.0
// Microsoft Visual Studio 2005
// C# console application
//

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace generic.exception
{
interface IFoo
{
void Foo();
}
class MyOwnException : ApplicationException
{
public MyOwnException( string message ) : base( message ) {}
}
class GenericCatch< T > where T : class, IFoo, new()
{
public static void CatchInFoo()
{
try
{
T t = new T();
t.Foo();
}
catch ( MyOwnException e )
{
Console.WriteLine( "GenericCatch.CatchInFoo catch (
MyOwnException )" );
Console.WriteLine( "e.Message: " + e.Message );
}
}
public static T CatchInConstructor()
{
try
{
T t = new T();
t.Foo();
}
catch ( MyOwnException e )
{
Console.WriteLine( "GenericCatch.CatchInConstructor catch (
MyOwnException )" );
Console.WriteLine( "e.Message: " + e.Message );
}
catch ( ApplicationException e )
{
Console.WriteLine( "GenericCatch.CatchInConstructor catch (
ApplicationException )" );
Console.WriteLine( "Exception of type: " + e.GetType().ToString() );
Console.WriteLine( "e.Message: " + e.Message );
}
return null;
}
}
class ThrowInConstructor : IFoo
{
public ThrowInConstructor()
{
Console.WriteLine( "ThrowInConstructor.Constructor() throw new
MyOwnException()" );
throw new MyOwnException( "MyOwnException in Constructor()" );
}
public void Foo()
{
}
}
class ThrowInFoo : IFoo
{
public ThrowInFoo()
{
}
public void Foo()
{
Console.WriteLine( "ThrowInFoo.Foo() throw new MyOwnException()" );
throw new MyOwnException( "MyOwnException in Foo()" );
}
}
class Program
{
static void Main( string[] args )
{
try
{
Console.WriteLine( "Call ThrowInConstructor outside of generics" );
ThrowInConstructor t = new ThrowInConstructor();
}
catch( MyOwnException e )
{
Console.WriteLine( "outside of generics catch ( MyOwnException )" );
Console.WriteLine( "e.Message: " + e.Message );
}
Console.WriteLine();
GenericCatch<ThrowInFoo>.CatchInFoo();
Console.WriteLine();
GenericCatch<ThrowInConstructor>.CatchInConstructor();
}
}
}

/*
Console application output:
----------

Call ThrowInConstructor outside of generics
ThrowInConstructor.Constructor() throw new MyOwnException()
outside of generics catch ( MyOwnException )
e.Message: MyOwnException in Constructor()

ThrowInFoo.Foo() throw new MyOwnException()
GenericCatch.CatchInFoo catch ( MyOwnException )
e.Message: MyOwnException in Foo()

ThrowInConstructor.Constructor() throw new MyOwnException()
GenericCatch.CatchInConstructor catch ( ApplicationException )
Exception of type: System.Reflection.TargetInvocationException
e.Message: Exception has been thrown by the target of an invocation.
*/
 
M

Mattias Sjögren

Vladimir,
----------
The INCONSISTENCE is:

Exception "MyOwnException" thrown from constructor of "ThrowInConstructor",
somehow TURNS INTO "TargetInvocationException" and is NOT caught by
"catch(MyOwnException)" block!!!
----------

That's because

new T()

compiles to

Activator.CreateInstance<T>()

and that method is documented as throwing a TargetInvocationException
if the constructor throws.


Mattias
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top