3

The code below does not compile:

 public static class MyExtensions
    {
        public static Bar<M> Convert<T,M>(this Foo<T> list)
        {
            return new Bar<M>();
        }
    }


    public class Program
    {
        static void Main(string[] args)
        {
            Foo<int> foo = new Foo<int>();

            foo.Convert<double>();
        }
    }

I have to explicitely specify Foo's generic type:

foo.Convert<int, double>();

Specifying the type during method call would not be necessary, if the extension method had a single generic parameter.

Why? Can I create such an extension method that does not require me to specify Foo's parameter?

emregon
  • 388
  • 1
  • 7
  • 18

1 Answers1

5

Why?

Type argument inference is all or nothing: you've got to either specify all the type arguments, or none of them, on each method call.

The M type parameter can't be inferred, because it doesn't occur anywhere in the parameter list.

A few options:

  • Chain two methods together, so that the first can use type inference and the second will let you specify the type argument for M:

    Bar<double> bar = foo.CreateConverter()   // Implicitly CreateConverter<int>
                         .ConvertTo<double>() // Specify that you want a Bar<double>
    

    This would require a new intervening type, e.g. Converter<T> to be returned by CreateConverter. That would have a regular instance method of ConvertTo<M>.

  • Add a parameter of type M to the Convert method:

    public static Bar<M> Convert<T, M>(this Foo<T> list, M ignored)
    

    ... you can then call the method as:

    Bar<double> bar = foo.Convert(default(double));
    

    That's somewhat smelly, admittedly.

  • Don't use an extension method, but a regular static generic method in a generic type - where both the type and the method have a single type parameter:

    public static class Converters<M>
    {
        public static Bar<M> Create<T>(Foo<T> foo) { ... }
    }
    

    then invoke it as:

    Bar<double> bar = Converters<double>.Create(foo);
    

    The type argument for the method can be inferred from foo, and you're specifying the type argument for the type explicitly.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194