クラスメソッドと同じシグネチャを持つ拡張メソッドを呼び出す方法を見つけましたが、あまり洗練されていないようです。拡張メソッドをいじってみると、文書化されていない動作に気づきました。サンプルコード:
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();
}
}
私が気づいたのは、拡張メソッド内から2番目のメソッドを呼び出すと、シグニチャにも一致するクラスメソッドがあったとしても、シグニチャに一致する拡張メソッドが呼び出されるということです。たとえば上記のコードで、ExtFunc()を呼び出し、次にele.GetDesc()を呼び出すと、期待される文字列 "Base GetDesc"ではなく、戻り文字列 "Extension GetDesc"が返されます。
コードのテスト:
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
これにより、クラスメソッドと拡張メソッドの間を自由に行き来することができますが、希望する「スコープ」に到達するには、重複する「パススルー」メソッドを追加する必要があります。ここでは、より良い言葉がないため、これをスコープと呼びます。うまくいけば、誰かが実際にそれが何と呼ばれるかを私に知らせることができます。
1つまたは2つのメソッドが同じシグネチャを持つ複数のメソッドのパススルーとして機能することを期待して、デリゲートをそれらに渡すというアイデアで私がもてなした私の「パススルー」メソッド名から推測したかもしれません。残念ながら、デリゲートがアンパックされると、別の拡張メソッドの内部からでも、拡張メソッドよりも常にクラスメソッドを選択したわけではありませんでした。「スコープ」はもはや重要ではありません。ActionとFuncのデリゲートはあまり使用していませんので、経験豊富な誰かがその部分を理解できるかもしれません。