Friday, August 15, 2008

A Little Bit Regret for Generic in C#

In our project, I defined the ThrowHelper helper class to help us throw the customized exception. For instance, I defined a exception as below:

public class EmployeeException : ApplicationException

{

    public EmployeeException()

        : base()

    { }

 

    public EmployeeException(string message)

        : base(message)

    { }

 

    public EmployeeException(string message, Exception innerException)

        : base(message, innerException)

    { }

}

 

Then we might define the method to throw it to be invoked by other developer conveniently:

public static class ThrowHelper

{

    public static EmployeeException ThrowEmployeeException(string message)

    {

        LogService.Error(message);

        throw new EmployeeException(message);

    }

 

    public static EmployeeException ThrowEmployeeException(string message, Exception innerException)

    {

        LogService.Error(message, innerException);

        throw new EmployeeException(message, innerException);

    }

}

 

The problem is that we need to add the method such as before if we defined a number of customized exceptions. It’s tedious. The developer must dislike this way whenever.

Can we use the generic type to solve this problem? For example, we may define a new version method using generic type as below:

public static class ThrowHelperGeneric<TCustomException>

    where TCustomException : ApplicationException, new()

{

    public static TCustomException ThrowCustomException(string message)

    {

        LogService.Error(message);

        throw new TCustomException(message);

    }

 

    public static TCustomException ThrowCustomException(string message, Exception innerException)

    {

        LogService.Error(message, innerException);

        throw new TCustomException(message, innerException);

    }

}

 

Opps, it’s regretful. It can’t support to invoke constructor with parameter based on .Net framework. We have to use the reflection technology to solve it:

public static class ThrowHelperGeneric<TCustomException>

    where TCustomException : ApplicationException, new()

{

    public static TCustomException ThrowCustomException(string message)

    {

        LogService.Error(message);

        TCustomException exception = (TCustomException)typeof(TCustomException).GetConstructor(new Type[] { typeof(string) }).

            Invoke(new object[] { message });

 

        throw exception;

    }

 

    public static TCustomException ThrowCustomException(string message, Exception innerException)

    {

        LogService.Error(message, innerException);

        TCustomException exception = (TCustomException)typeof(TCustomException).GetConstructor(new Type[] { typeof(string), typeof(Exception) }).

            Invoke(new object[] { message, innerException });

 

        throw exception;

    }

}

 

It’s a terrible choice. I don’t like to do in this way. Even though we can use new() in the where constraint, how come Microsoft can’t provide the similiar operator or keyword in the where constraint to constrain the type of the parameter in the constructor? Like this:

public static class ThrowHelperGeneric<TCustomException>

    where TCustomException : ApplicationException, new(), new(string), new(string, Exception)

{

    public static TCustomException ThrowCustomException(string message)

    {

        LogService.Error(message);

        throw new TCustomException(message);

    }

 

    public static TCustomException ThrowCustomException(string message, Exception innerException)

    {

        LogService.Error(message, innerException);

        throw new TCustomException(message, innerException);

    }

}

I don’t know whether it will support this function in the furture version with C#. Is it too difficult?

No comments: