-3

I have the following methods

public static EnumerableAssertions<T> AssertThat<T>(IEnumerable<T> collection)
{
    Debug.WriteLine("Enumerable!");
    return new EnumerableAssertions<T>(collection);
}

public static ObjectAssertions<T> AssertThat<T>(T value) where T : class
{
    Debug.WriteLine("Generic fallback!");
    return new ObjectAssertions<T>(value);
}

But why does the following call resolve to the generic fallback?

List<object> list = null;
AssertThat(list);

From my understanding the overload for IEnumerable<T> should be more specific than the generic T : class but C# seems to see that differently. If I add an overload for the exact type List<T> it works just fine, but of course I don't want to add specific overloads for every type inheriting IEnumerable<T>

  • 1
    Why would you want to use a `List` anyway? –  Dec 06 '22 at 12:01
  • @Deleted make it a List if you like that better and the problem won't change. It's an example. – Ralf Dec 06 '22 at 12:10
  • As an aside, which overload would you have wanted it to select if you provided a `string`? Bearing in mind that that type *happens* to be `IEnumerable` but that's not the most common way of thinking about it. – Damien_The_Unbeliever Dec 06 '22 at 12:10
  • 2
    _Apples and oranges_. `AssertThat(T value)` contains the explicit constraint `where T : class` whilst `AssertThat(IEnumerable collection)` has **no** explicit constraints at all. `AssertThat(list);` is most likely resolving to the generic one because `List<>` is an reference type and is more in line with `where T : class` than an unrestricted `IEnumerable` –  Dec 06 '22 at 12:19
  • Yeah, it's just an example. And @Damien_The_Unbeliever you are right, `string` is not covered by this. In my logic I would have expected `string` to use the `IEnumerable` overload, because that is (only considering the two overloads above) the most specific. If I want to have a specific overload for `string` I would need to add an explicit overload for the (exact) type `string` – Oliver Saggau Dec 06 '22 at 12:21
  • @Deleted I know these are apples and oranges, but even the overload `EnumerableAssertions AssertThat(TCollection value) where TCollection : IEnumerable` with an explicit constraint won't be favored by C# over the generic fallback – Oliver Saggau Dec 06 '22 at 12:26
  • 1
    _"I know these are apples and oranges, but even the overload"_ - Irrelevant. The problem is with your code not theirs. –  Dec 06 '22 at 12:29
  • 1
    @Ralf _”make it a List if you like that better and the problem won't change”_ - a shame you didn’t suggest List in your moment of sarcasm and you would have hilighted the issue with the OP’s code. –  Dec 06 '22 at 15:17
  • 1
    _["Editing a question so that the provided answers are invalid is not the right way for the original user to get assistance. If they have further questions, they should post a new question, not invalidate the help they've already been given."](https://meta.stackoverflow.com/a/351629/585968)_. I have rolled back your question to the time prior to any answer below. –  Dec 06 '22 at 23:39

1 Answers1

0

OP:

From my understanding the overload for IEnumerable should be more specific than the generic T : class but C# seems to see that differently

Apples and oranges.

This method:

public static ObjectAssertions<T> AssertThat<T>(T value) where T : class

...contains the explicit constraint:

where T : class

...whilst:

public static EnumerableAssertions<T> AssertThat<T>(IEnumerable<T> collection)

...has no explicit constraints at all.

OP:

But why does the following call resolve to the generic fallback?

The code:

List<object> list = null;
AssertThat(list);

...is most likely resolving to the generic one (the one with the where T : class) because List<> is a reference type and is more in line with where T : class than an unrestricted IEnumerable<T>.