Rocky
Rocky

Reputation: 182

Getting type arguments cannot be inferred error from function that accepts 2 type args

Okay, I need to be able to pass in an anonymous method and an exception type to check against. Here's a stripped out version of what I'm trying now

public T MyMethod<T,E>(Func<T> action, E ExceptionType, int param2, int param3 = 3) where E : Exception
{
    try
    {
    //Some code here
    }
    catch(Exception ex)
    {
        if(ex.GetType() == typeof(ExceptionType))
        {
         //Do something
        }
        else
        {
          //Do something else
        }
    }
}

I'm trying to call the method like this

Retry(()=>OtherMethod("input"),typeof(Exception),33,9);

And I keep getting the same error. "The type arguments for method X cannot be inferred from the usage. Try specifying the type arguments explicitly"

The idea is to check to see if an exception thrown inside MyMethod matches the type of exception that was passed in as the second argument, and take an action based on whether it does or not. I can't just hard code the type because this is to be used in a library and the type of exception to check for will not always be the same.

What can I change to accomplish what I am trying?

EDIT: I've also tried to call the method like so..

Retry(()=OtherMethod(),new Exception(),10,10)

But I get the same issue.

Upvotes: 0

Views: 290

Answers (2)

Eric Lippert
Eric Lippert

Reputation: 660513

Servy's answer is correct. Some thoughts on how to fix your problem:

First option: take a type:

public T MyMethod<T>(Func<T> action, Type exceptionType)
{
    ...
    catch(Exception ex)
    {
        if(ex.GetType() == exceptionType)

Second option: take a type parameter:

public T MyMethod<T, E>(Func<T> action)
  where E : Exception 
{
    ...
    catch(Exception ex)
    {
        if(ex.GetType() == typeof(E))

This solution has a problem: there is no basis upon which to infer the type parameter E, so the caller cannot use type inference.

A third option:

public T MyMethod<T>(Func<T> action, Exception example)
{
    ...
    catch(Exception ex)
    {
        if(ex.GetType() == example.GetType())

Yuck. Passing in an object just so that you can extract its type is weird.

All solutions have a problem with the comparison:

if(ex.GetType() == exceptionType)
if(ex.GetType() == typeof(E))
if(ex.GetType() == example.GetType())

This is problematic; suppose the exception type is AnimalException and ex is of type GiraffeException, which derives from AnimalException. These tests will fail, since the types are not equal, and that's an equality check. If you go with this approach, consider whether an exact match of types is what you really want.

I was hoping to be able to pass in a Type but have it restricted to only types that inherit from Exception

Oh, well, why didn't you say so?

public T MyMethod<T>(Func<T> action, Type exceptionType)
{
    if (!typeof(Exception).IsAssignableFrom(exceptionType))
        throw new ArgumentException("exceptionType must represent a type derived from or equal to Exception");

Easy peasy. Don't try to capture everything in the type system. Your callers who violate this rule will discover it quickly and fix the problem.

Upvotes: 1

Servy
Servy

Reputation: 203840

The expression typeof(Exception) evaluates to Type. Type doesn't meet the criteria for the type that it needs to extend Exception.

The method is expecting you to pass an instance of some kind of exception, not a Type object that is an exception.

If you want to pass the type itself, don't try to infer the generic arguments - explicitly specify the exception as the generic type argument. If you want to pass a Type, write the method to accept one.

Upvotes: 2

Related Questions