8

If I have a method as such:

public void Foo<T1, T2>(T1 list)
    where T1 : IList<T2>
    where T2 : class
{
    // Do stuff
}

Now if I have:

IList<string> stringList = new List<string>();
List<object> objectList = new List<object>();
IList<IEnumerable> enumerableList = new List<IEnumerable>();

Then the compiler cannot resolve the generics to select and this fails:

Foo(stringList);
Foo(objectList);
Foo(enumerableList);

And you have to explicitly specify the generics to use as such:

Foo<IList<string>, string>(stringList);
Foo<IList<object>, object>(objectList);
Foo<List<object>, object>(objectList);
Foo<IList<IEnumerable>, IEnumerable>(enumerableList);
Cornelius
  • 3,526
  • 7
  • 37
  • 49
  • 8
    Side comment, but do you actually need `T1`? Couldn't you do `public void Foo(IList list) where T : class`? – lc. Feb 22 '13 at 07:21
  • 1
    possible duplicate of [No type inference with generic extension method](http://stackoverflow.com/questions/7171067/no-type-inference-with-generic-extension-method) – Daniel Hilgarth Feb 22 '13 at 07:23
  • Check Erics answer in the linked question and the blog post linked therein. – Daniel Hilgarth Feb 22 '13 at 07:24
  • 2
    @Daniel: a reason to *not close* this question, even though it is a duplicate, is its simple and minimalistic code sample and problem description. The original question is really hard to understand. – Stefan Steinegger Feb 22 '13 at 07:31
  • 2
    @lc.: Most likely, you are right with your comment, but there are scenarios where something like this makes sense. One example would be fluent extension methods for a whole class hierarchy where the extension method should return the concrete subtype instead of the common interface. Imagine `Foo` as an extension method the returns `T1`. In that case, the following would be valid: `new List<...>().Foo(...).AddRange()`. (Note: `AddRange` is defined on `List`, not on `IList`. So, if `Foo` would return `IList` instead, that code would no longer work. – Daniel Hilgarth Feb 22 '13 at 07:33
  • @StefanSteinegger: Indeed, I did a bad job in extracting the underlying problem back than... – Daniel Hilgarth Feb 22 '13 at 07:34
  • @StefanSteinegger: I decided to copy the answer from Eric here. – Daniel Hilgarth Feb 22 '13 at 07:37
  • @DanielHilgarth I totally agree; I was only commenting on the code as presented because the method neither returned a value nor was an extension method. There didn't really seem to be a purpose for the type argument other than to complicate matters. – lc. Feb 22 '13 at 07:39
  • @lc in the original code this is an extension method and instance of and with a return type `MyClass` and that is why I want the `where T1 : IList where T2 : class` This code only served to abstract my problem in a unencumbered way. – Cornelius Feb 23 '13 at 07:30

1 Answers1

5

Generic method type inference deliberately does not make any deductions from the constraints. Rather, deductions are made from the arguments and the formal parameters, and then the deduced type arguments are checked against the constraints.

For a detailed discussion of some of the design issues around constraints and method signatures, including several dozen people telling me that I'm wrong to think that the existing design is sensible, see my article on the subject:

http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

This is an exact copy of Eric Lippert's answer to a similar question.
I decided to copy it, because this question is more concise and clear.

Community
  • 1
  • 1
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443