最も手間がかからない方法は、おそらく、必要なメソッドを式ツリーでキャプチャしてから、メソッド参照を見つけるために掘り下げます。これを 1 回実行してジェネリック メソッド定義を取得し、結果をキャッシュして、必要に応じて再利用できます。
Expression<Func<IQueryable<int>, int>> getCount = p => p.Count();
MethodInfo countMethod = ((MethodCallExpression)getCount.Body).Method.GetGenericMethodDefinition();
これには、 API の変更 (より多くの "Count" メンバーの追加など) に対してある程度回復力があるという利点があります。返されるメソッドは、コンパイル時に式がバインドされるメソッドになります。
必要に応じて、この動作をユーティリティ メソッドに抽出できます。
public static MethodInfo MethodOf(Expression<Action> accessExpression, bool dropTypeArguments = false)
{
if (accessExpression == null)
throw new ArgumentNullException("accessExpression");
var callExpression = accessExpression.Body as MethodCallExpression;
if (callExpression == null)
throw new ArgumentException("Expression body must be a method call.", "accessExpression");
var method = callExpression.Method;
if (dropTypeArguments && method.IsGenericMethod)
return method.GetGenericMethodDefinition();
return method;
}
public static MethodInfo MethodOf<TInstance>(Expression<Action<TInstance>> call, bool dropTypeArguments = false)
{
if (call == null)
throw new ArgumentNullException("call");
var callExpression = call.Body as MethodCallExpression;
if (callExpression == null)
throw new ArgumentException("Expression body must be a method call.", "call");
var method = callExpression.Method;
if (dropTypeArguments && method.IsGenericMethod)
return method.GetGenericMethodDefinition();
return method;
}
静的スタイルの呼び出しには最初のオーバーロードを使用し、インスタンス スタイルの呼び出しには後者を使用します。
var countMethod1 = Extensions.MethodOf(() => Queryable.Count(default(IQueryable<int>)), dropTypeArguments: true);
var countMethod2 = Extensions.MethodOf((IQueryable<int> p) => p.Count(), dropTypeArguments: true);
型引数を保持するには (たとえば、Count<int>()
の代わりに解決するにはCount<T>()
)、単に引数を省略するdropTypeArguments: true
か、 に設定しfalse
ます。
これらはそれほど包括的ではないことに注意してください。たとえば、宣言型のジェネリック パラメーターをドロップしません (メソッド自体のみ)。自由に使用、拡張、または破棄してください:)。