He encontrado una forma de invocar un método de extensión con la misma firma que un método de clase, sin embargo, no parece muy elegante. Al jugar con los métodos de extensión, noté un comportamiento indocumentado. Código de muestra:
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();
}
}
Lo que noté fue que si llamaba a un segundo método desde dentro de un método de extensión, llamaría al método de extensión que coincidía con la firma, incluso si había un método de clase que también coincidía con la firma. Por ejemplo, en el código anterior, cuando llamo a ExtFunc (), que a su vez llama a ele.GetDesc (), obtengo la cadena de retorno "Extension GetDesc" en lugar de la cadena "Base GetDesc" que esperaríamos.
Probando el código:
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
Esto le permite ir y venir entre métodos de clase y métodos de extensión a voluntad, pero requiere la adición de métodos de "paso a través" duplicados para llegar al "alcance" que desea. Lo llamo alcance aquí a falta de una palabra mejor. Espero que alguien me pueda decir cómo se llama realmente.
Es posible que haya adivinado por los nombres de mis métodos de "paso a través" que también jugué con la idea de pasarles delegados con la esperanza de que uno o dos métodos pudieran actuar como un paso para varios métodos con la misma firma. Desafortunadamente, no fue así, ya que una vez que se descomprimió el delegado, siempre eligió el método de clase sobre el método de extensión, incluso desde dentro de otro método de extensión. El "alcance" ya no importaba. Sin embargo, no he usado mucho a los delegados de Action y Func, así que tal vez alguien con más experiencia pueda resolver esa parte.