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 Executer
which 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.
- It compiles OK when I use
base.Execute(analytics);
instead, but I need override method, so it is not an option. - It compiles OK when I use
Execute(INonAnalytics nonAnalytics)
instead ofpublic 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.