I have found a way to invoke an extension method with the same signature as a class method, however it does not seem very elegant. When playing around with extension methods I noticed some undocumented behavior. Sample code:
public static class TestableExtensions
{
public static string GetDesc(this ITestable ele)
{
return "Extension GetDesc";
}
public static void ValDesc(this ITestable ele, string choice)
{
if (choice == "ext def")
{
Console.WriteLine($"Base.Ext.Ext.GetDesc: {ele.GetDesc()}");
}
else if (choice == "ext base" && ele is BaseTest b)
{
Console.WriteLine($"Base.Ext.Base.GetDesc: {b.BaseFunc()}");
}
}
public static string ExtFunc(this ITestable ele)
{
return ele.GetDesc();
}
public static void ExtAction(this ITestable ele, string choice)
{
ele.ValDesc(choice);
}
}
public interface ITestable
{
}
public class BaseTest : ITestable
{
public string GetDesc()
{
return "Base GetDesc";
}
public void ValDesc(string choice)
{
if (choice == "")
{
Console.WriteLine($"Base.GetDesc: {GetDesc()}");
}
else if (choice == "ext")
{
Console.WriteLine($"Base.Ext.GetDesc: {this.ExtFunc()}");
}
else
{
this.ExtAction(choice);
}
}
public string BaseFunc()
{
return GetDesc();
}
}
What I noticed was that if I called a second method from inside an extension method, it would call the extension method that matched the signature even if there was a class method that also matched the signature. For example in the code above, when I call ExtFunc(), which in turn calls ele.GetDesc(), I get the return string "Extension GetDesc" instead of the string "Base GetDesc" that we would expect.
Testing the code:
var bt = new BaseTest();
bt.ValDesc("");
//Output is Base.GetDesc: Base GetDesc
bt.ValDesc("ext");
//Output is Base.Ext.GetDesc: Extension GetDesc
bt.ValDesc("ext def");
//Output is Base.Ext.Ext.GetDesc: Extension GetDesc
bt.ValDesc("ext base");
//Output is Base.Ext.Base.GetDesc: Base GetDesc
This allows you to bounce back and forth between class methods and extension methods at will, but requires the addition of duplicate "pass-through" methods to get you into the "scope" you desire. I am calling it scope here for lack of a better word. Hopefully someone can let me know what it is actually called.
You might have guessed by my "pass-through" method names that I also toyed with the idea of passing delegates to them in the hopes that a single method or two could act as a pass-through for multiple methods with the same signature. Unfortunately it was not to be as once the delegate was unpacked it always chose the class method over the extension method even from inside another extension method. "Scope" no longer mattered. I have not used Action and Func delegates very much though so maybe someone more experienced could figure that part out.