7

Possible Duplicate:
No type inference with generic extension method

I have a generic interface, and two concrete implementations of it.

I then have a method which is an extension method on a collection of objects implementing that interface, which is supposed to process the collection and return the processed collection.

The processing operation does not change the objects nor produce new ones, so I want the output from that method to be the same type as the input.

In other words, I don't want the output from the method to be a collection of the interface type, rather the actual concrete type I passed in.

However, this leads to a problem with type inference when calling the method.

I'll illustrate with a LINQPad example:

void Main()
{
    var intervals = new Interval<int>[]
    {
        new Interval<int>(),
        new Interval<int>(),
    };

    var ordered1 = intervals.Process(); // error 1
    // var ordered2 = Extensions.Process(intervals); // error 2
}

public static class Extensions
{
    public static IEnumerable<TInterval> Process<TInterval, T>(
        this IEnumerable<TInterval> intervals)
        where TInterval : IInterval<T>
    {
        return intervals;
    }
}

public interface IInterval<T> { }
public class Interval<T> : IInterval<T> { }

This gives me the following two compile-time error, you have to comment out and in the relevant lines to provoke the two messages:

error 1:
'Interval<int>[]' does not contain a definition for 'Process' and no extension method 'Process' accepting a first argument of type 'Interval<int>[]' could be found (press F4 to add a using directive or assembly reference)

error 2:
The type arguments for method 'Extensions.Process<TInterval,T>(System.Collections.Generic.IEnumerable<TInterval>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

The reasons, or so I assume, is that the compiler is not looking "deeply enough" when analyzing whether the extension method will fit.

If I change the extension method to:

public static IEnumerable<IInterval<T>> Process<T>(
    this IEnumerable<IInterval<T>> intervals)
{
    return intervals;
}

Then it compiles, but thus the output is:

IEnumerable<IInterval<T>> result = ...

and not:

IEnumerable<Interval<int>> result = ...

Of course, if I specify the types when calling, like this:

var ordered = intervals.Process<IInterval<int>, int>();

... then it works, but that's not really all that better (IMO.) Are there any way to trick the compiler into inferring the type for me?

Basically, I want to:

  1. Get the type I called the method with out of it, instead of the results being typed to the interface
  2. Avoid having to keep telling the compiler that yes, this is indeed another call using these types. The reason for this is that the method will be part of LINQ-like call chain, so either I have to cast back to the known type after each call, or specify the full types for each call.
Community
  • 1
  • 1
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • It did strike me while posting this that it seemed eerily familiar with a question I've seen before, but my search-fu is failing me. Please post duplicates if you find them, and I'll get rid of this question myself in that case. – Lasse V. Karlsen Nov 17 '11 at 11:56
  • Ok, now I got the code right. Sorry for the messed up copy-paste version I posted to begin with. – Lasse V. Karlsen Nov 17 '11 at 12:05
  • I think this is the one you're looking for http://stackoverflow.com/questions/7171067/no-type-inference-with-generic-extension-method/7171527#7171527 – Chris Chilvers Nov 17 '11 at 12:22
  • Yes and no. Certainly did answer my question, but not the one I remember. Still, *sigh*, duplicate *and* the answer is "not possible". Closing as duplicate. – Lasse V. Karlsen Nov 17 '11 at 12:23
  • Could you explain what the problem is with the second solution? It's lost on me... – Tim Rogers Nov 17 '11 at 12:24
  • I'd just rather avoid having to write out the types all the times. This is part of a call chain, so the full chain will look like: `var result = collection.Process1, int>().Process2, int>().Process3, int>(), ...` – Lasse V. Karlsen Nov 17 '11 at 12:25
  • I meant the problem with declaring it as `public static IEnumerable> Process(this IEnumerable> intervals) {}`. I'm interested even though you've closed it. – Tim Rogers Nov 17 '11 at 12:26

0 Answers0