1

I'm reading the famous archived article by Eric Lippert Constraints are not part of the signature. In this article there is an example of code that I'm trying to run in a clean new solution using .NET 2.0:

class Program
{
    class Animal { }
    class Mammal : Animal { }
    class Giraffe : Mammal { }
    class Reptile : Animal { }

    static void Foo<T>(T t) where T : Reptile
    {

    }
    static void Foo(Animal animal)
    {

    }

    static void Main(string[] args)
    {
        Foo(new Giraffe());
        Console.ReadLine();
    }
}

In the article Eric says that:

Most people assume that overload resolution will choose the second overload. In fact, this program produces a compile error saying that T cannot be Giraffe. Is this a compiler bug? No, this behaviour is correct according to the spec.

When I run the code using .NET 2.0 I have no error, the method Foo(Animal animal) is called. The same method called when I pass null instead of Giraffe. I understand that the C# team possibly changed something later, but I use .NET 2.0 here! Using C# 9 I see the same behavior. My question is how I can reproduce the error that Eric mentioned in this article? If I can't reproduce it then I may face the error unexpectedly some day in certain circumstances.

usr2020
  • 324
  • 2
  • 8
  • That article is 10 years old. Try using a C# compiler that existed at the time the article was written. – Robert Harvey Oct 22 '20 at 15:53
  • 1
    See also https://codeblog.jonskeet.uk/2010/10/28/overloading-and-generic-constraints/ – Robert Harvey Oct 22 '20 at 15:54
  • 1
    And also: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.3/improved-overload-candidates – Robert Harvey Oct 22 '20 at 15:56
  • @Robert Harvey: do you mean that if I run this code in Visual Studio 2005 with .NET 2.0 I will see the described by Eric behavior? Currently I run it in VS 2019\.NET 2.0. I was under impression that such things must depend only on framework, not on a specific version of VS. – usr2020 Oct 22 '20 at 16:00
  • What version of C# are you running? The overload resolution is most likely taking place in the compiler, not the framework. – Robert Harvey Oct 22 '20 at 16:03
  • 1
    You should read [this article](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.3/improved-overload-candidates), which I previously linked. I found it in the comments section of the Jon Skeet article [here](https://codeblog.jonskeet.uk/2010/10/28/overloading-and-generic-constraints/#comment-55342); that article I also previously linked. – Robert Harvey Oct 22 '20 at 16:04
  • 1
    A compile error has nothing to do with the framework. It has everything to do with the version of the compiler you use and that's tied to the version of Visual Studio. – juharr Oct 22 '20 at 16:12
  • @Robert Harvey: "What version of C# are you running?" In the project's build property it says "Language version: automatically selected based on framework version". – usr2020 Oct 22 '20 at 16:15
  • @juharr: I didn't know that. So if I migrate a project that was developed in VS 2005 to VS2019 I may have a plenty of work editing the code to work as expected in VS2005? – usr2020 Oct 22 '20 at 16:18
  • 2
    Generally speaking, code written in VS 2005 is forward-compatible in VS2019. There should be minimal changes required to make your code work. – Robert Harvey Oct 22 '20 at 16:23
  • There is a difference between language version and compiler version. Compiler of latest version can be instructed to compile code of older language versions (backward compatibility). In that case it won't for example accept constructs that are valid in later version but were not valid at target language version. – Evk Oct 22 '20 at 16:26
  • Eventually I will move that over to ericlippert.com, but I'm not sure what to do with the dauntingly huge number of comments saying I am WRONG WRONG WRONG for believing the original rule to be a good rule. Apparently eventually the C# team came to believe it a bad rule too! – Eric Lippert Oct 23 '20 at 22:32
  • 1
    @Eric Lippert: Eric, I think you were right with your solution. Here is a question on stackoverflow that shows that the current solution works in one case and doesn't in the other case: https://stackoverflow.com/questions/60754529/how-to-explain-this-call-is-ambiguous-error%20:) Here the code from the question can be quickly tested: https://dotnetfiddle.net/uddP67 – usr2020 Oct 24 '20 at 17:52

1 Answers1

1

The comments under the question give a general answer, but for those who need more details I think this link that leads to the up-to-date description of Type Interface in C# will be useful: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#type-inference The article is bigger than it is allowed to publish here and I think that over time it will be updated while posting it here may lead later to outdated posted information in this answer. Instead of publishing the entire article I just put here the list of topics this article describes:

  • Type inference process phases;
  • Output type inferences;
  • Explicit parameter type inferences;
  • Exact inferences;
  • Lower-bound inferences;
  • Upper-bound inferences;
  • Fixing;
  • Inferred return type;
  • Type inference for conversion of method groups;
  • Finding the best common type of a set of expressions;
  • Overload resolution;
  • Applicable function member;
  • Better function member;
  • Better conversion from expression;
  • Exactly matching Expression;
  • Better conversion target;
  • Overloading in generic classes;
  • Compile-time checking of dynamic overload resolution;
  • Function member invocation;
  • Invocations on boxed instances.
V. S.
  • 1,086
  • 14
  • 14