0

Yesterday I saw strange C# compiler behavior when dealing with inheritance and overload resolution. Today I tried to reproduce it in new project and I was able to. You can see full experimental project using this repository. But, basically I have two classes. ExecuterBase is as following:

public class ExecuterBase
{
    public virtual void Execute(Analytics analytics)
    {
        analytics?.Execute();
    }
}

And Executerwhich inherits ExecuterBase is as below:

public class Executer : ExecuterBase
{
    public void Experiment()
    {
        var analytics = new Analytics();
        Execute(analytics);
    }

    public void Execute<TNonAnalytics>(TNonAnalytics nonAnalytics)
        where TNonAnalytics : INonAnalytics
    {
        nonAnalytics?.Execute();
    }

    public override void Execute(Analytics analytics)
    {
        // some additional staff goes here
        base.Execute(analytics);
    }
}

Analytics and INonAnalytics are almost empty just for demonstration:

public class Analytics
{
    public void Execute()
    { }
}

public interface INonAnalytics
{
    void Execute();
}

Analytics doesn't implement INonAnalytics. The problem is that I get compiler error at Execute(analytics); line inside Experiment method.

The type 'Experiments.InheritanceAndOverload.Analytics' cannot be used as type parameter 'TNonAnalytics' in the generic type or method 'Executer.Execute(TNonAnalytics)'. There is no implicit reference conversion from 'Experiments.InheritanceAndOverload.Analytics' to 'Experiments.InheritanceAndOverload.INonAnalytics'

Obviously it tries to use public void Execute<TNonAnalytics>(TNonAnalytics nonAnalytics) where it should use overrided method. Interestingly enough it compiles OK when you put all the methods inside same class. You can see that class - SingleExecuter.cs - in the repository.

  1. It compiles OK when I use base.Execute(analytics); instead, but I need override method, so it is not an option.
  2. It compiles OK when I use Execute(INonAnalytics nonAnalytics) instead of public void Execute<TNonAnalytics>(TNonAnalytics nonAnalytics) - but in original project I have more than one type constraints and also I use generic type parameter inside this method, so it is also not an option.

Even if there is some workaround I want to learn reason why compiler behaves like this instead of this workaround. May be there is some C# language specifications that applies here and I miss them. I suspect it is a compiler bug.

Adil Mammadov
  • 8,476
  • 4
  • 31
  • 59
  • What is the error – TheGeneral Jun 12 '19 at 09:52
  • This is just about overload resolution, there are complex rules around how this works. When you have the generic method, the compiler will try to use it first, otherwise it will use the method from the base class. – DavidG Jun 12 '19 at 09:55
  • @DavidG I understand, but when it doesn't match it should try to find matching method instead of giving me compiler error, don't you agree? – Adil Mammadov Jun 12 '19 at 09:56
  • Not necessarily, the rules are far more complex than you might assume. See: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#overload-resolution – DavidG Jun 12 '19 at 09:58
  • @DavidG thank you, I will read it, but before I read - does it answer why it works when I put all that methods in same class? – Adil Mammadov Jun 12 '19 at 10:04
  • @HansPassant no, I have one Analytics type. You can easily clone the repository, it is very small – Adil Mammadov Jun 12 '19 at 10:14
  • It would perhaps be worth referring to this post which describes something very close to your issue: https://blogs.msdn.microsoft.com/ericlippert/2009/12/10/constraints-are-not-part-of-the-signature/ In short, constraints on generic type parameters are *not* considered when determining the overload to use, so the generic method is chosen as the better matching overload (since it can be made to match the parameters exactly), and then later in the process it fails when the constraints are validated. – Iridium Jun 12 '19 at 11:03
  • @Iridium thank you for link, it seems very similar to my issue. But in my case it works when all the methods are in one class, so it is really confusing for me – Adil Mammadov Jun 12 '19 at 11:16
  • Did you try to use Analytics declaration instead of var? I mean: Analytics analytics = new Analytics(); instead of using var? – Adam Jachocki Jun 12 '19 at 12:37
  • @AdamJachocki it should not have any difference – Adil Mammadov Jun 12 '19 at 12:51
  • I found duplicate questions. And you can read "Inheritance" section of https://csharpindepth.com/Articles/Overloading for more info – Adil Mammadov Jun 12 '19 at 12:53
  • @AdilMammadov It SHOULD not :) – Adam Jachocki Jun 12 '19 at 13:00
  • @AdamJachocki I mean there is no difference :) – Adil Mammadov Jun 12 '19 at 13:26

0 Answers0