Ho trovato un modo per invocare un metodo di estensione con la stessa firma di un metodo di classe, tuttavia non sembra molto elegante. Quando ho giocato con i metodi di estensione ho notato alcuni comportamenti non documentati. Codice di esempio:
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();
}
}
Quello che ho notato è che se chiamassi un secondo metodo dall'interno di un metodo di estensione, chiamerebbe il metodo di estensione che corrisponde alla firma anche se ci fosse un metodo di classe che corrispondeva anche alla firma. Ad esempio nel codice sopra, quando chiamo ExtFunc (), che a sua volta chiama ele.GetDesc (), ottengo la stringa di ritorno "Extension GetDesc" invece della stringa "Base GetDesc" che ci aspetteremmo.
Testare il codice:
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
Ciò consente di rimbalzare avanti e indietro tra metodi di classe e metodi di estensione a piacimento, ma richiede l'aggiunta di metodi "pass-through" duplicati per entrare nello "ambito" desiderato. Lo chiamo ambito qui per mancanza di una parola migliore. Spero che qualcuno possa farmi sapere come si chiama effettivamente.
Potreste aver intuito dai miei nomi di metodo "pass-through" che ho anche accarezzato l'idea di passare loro delegati nella speranza che un singolo metodo o due potessero fungere da pass-through per più metodi con la stessa firma. Sfortunatamente non doveva essere come una volta che il delegato è stato decompresso, ha sempre scelto il metodo di classe rispetto al metodo di estensione anche dall'interno di un altro metodo di estensione. "Scope" non aveva più importanza. Non ho usato molto i delegati di Action e Func, quindi forse qualcuno più esperto potrebbe capire quella parte.