Search code examples
c#.netgeneric-type-argumentgeneric-type-parameters

C# Not Determining Type Arguments


I have a C# method that is requiring explicit type arguments, and I am getting this error:

error CS0411: The type arguments for method 'Test.TargetMethod<TObjectFactory, TResult>(TObjectFactory)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

I can normally work around this by specifying proper arguments (regular arguments, not type arguments), but in this case, I may have to state the type arguments explicitly. But I don't want to specify type arguments since it adds verbosity.

Please see the below example code, specifically the two calls to TargetMethod near the bottom. In the first invocation of TargetMethod, the type arguments should be obvious since I'm passing in a StringFactory, which only returns a string. (See the generic type constraints of TargetMethod.) Is there a way to get C# to realize that it has all it needs to know and shouldn't need type arguments? I'm wondering if I need to change the signature of TargetMethod so C# can understand what's happening. Thank you.

public interface IObjectFactory<out TResult>
{
    TResult Construct();
}

public class StringFactory : IObjectFactory<string>
{
    public string Construct() { return ""; }
}

public static class Test
{
    //I need to be able to pass in a generic factory to this method.
    //I also need it to return a generic result.
    //This is a mandatory part of the design, and on its own, it works fine.
    private static TResult TargetMethod<TObjectFactory, TResult>(TObjectFactory objectFactory)
        where TObjectFactory : IObjectFactory<TResult>
    {
        return objectFactory.Construct();
    }

    //This method can't easily call the other one.
    public static void EntryMethod()
    {
        StringFactory stringFactory = new StringFactory();
        //On the below line, how can I get C# to figure out that TargetMethod will return a string?
        string result1 = TargetMethod(stringFactory);//compilation error
        //I can do the below, but I don't want to have to specify type arguments each time.
        string result2 = TargetMethod<StringFactory, string>(stringFactory);
    }
}

Solution

  • On the below line, how can I get C# to figure out that TargetMethod will return a string?

    You can't. Look at your method declaration:

    TResult TargetMethod<TObjectFactory, TResult>(TObjectFactory objectFactory)
    

    Your parameters only refer to TObjectFactory, not TResult. Type inference only uses the arguments and parameters, not how the method result is used or the type constraints for the type parameters. Even though TObjectFactory is constrained to implement IObjectFactory<TResult>, that isn't used to infer the type argument for TResult.

    The type argument for TResult simply can't be inferred from the regular arguments, because the type parameter doesn't occur anywhere in the parameter list.

    An alternative would be to change the method to:

    TResult TargetMethod<TResult>(IObjectFactory<TResult> factory)
    

    After all, you don't really need to know TObjectFactory in your method, as far as we can see.

    (Or more simply, get rid of the interface entirely and use Func<T>, just using simple factory methods and constructing delegates from them where required...)