指定した型のTypeインスタンスを取得する場合は、C#typeof
キーワードを使用できます。しかし、参照によってメソッドのMethodInfo
を取得したい場合、何を使用できますか?
たとえば、シンプルなコンソールアプリがあります。 _Program.Main
_メソッドが含まれています。 methodinfoof(Program.Main)
のようなものを使用してMethodInfo
を取得したい。メソッド名が変更される可能性があるため、この問題があります。そのため、Type.GetMethodInfo(string MethodName)
だけを使用することはできません。
MethodInfo
を取得したい約10,000のメソッドがあるので、カスタム属性などをメソッドに追加することは解決策ではありません。
以前に投稿された回答を少し変更しましたが、このブログ投稿はあなたが求めていることを達成しているようです。 http://blog.functionalfun.net/2009/10/getting-methodinfo-of-generic-method.html
使用例は次のとおりです。
var methodInfo = SymbolExtensions.GetMethodInfo(() => Program.Main());
元の答えはこの質問に対するものでした。 https://stackoverflow.com/a/9132588/5827
非静的メソッドには式ツリーを使用できます。ここに例があります。
using System.Linq.Expressions;
using System.Reflection;
public static class MethodInfoHelper
{
public static MethodInfo GetMethodInfo<T>(Expression<Action<T>> expression)
{
var member = expression.Body as MethodCallExpression;
if (member != null)
return member.Method;
throw new ArgumentException("Expression is not a method", "expression");
}
}
次のように使用します。
MethodInfo mi = MethodInfoHelper.GetMethodInfo<Program>(x => x.Test());
Console.WriteLine(mi.Name);
Test()は、Programクラスで宣言されたメンバー関数です。
プロパティのゲッターとセッターをサポートしたい場合は、代わりにMemberExpression
とMemberInfo
を使用してください。
テストクラス
public class Foo
{
public void DoFoo()
{
Trace.WriteLine("DoFoo");
}
public static void DoStaticFoo()
{
Trace.WriteLine("DoStaticFoo");
}
}
そして、あなたはこのようなことをすることができます
MethodInfo GetMethodInfo(Action a)
{
return a.Method;
}
var foo = new Foo();
MethodInfo mi = GetMethodInfo(foo.DoFoo);
MethodInfo miStatic = GetMethodInfo(Foo.DoStaticFoo);
//do whatever you need with method info
更新
メソッドにいくつかのパラメータがある場合、@ Gregコメントごとに、Action<T>
、Action<T1, T2>
、Action<T1, T2, T3>
、またはFunc<T1>
を使用できます。不便なのは、 GetMethodInfo
のオーバーロードを書き込む必要があります。
私はこれが非常に古い投稿であることを知っていますが、これに対する簡単な解決策をまだ探している人のために捨てるつもりです。
_typeof(Program).GetMethods();
_
属性やパラメータの有無に関係なく、ProgramクラスのすべてのメソッドのMethodInfoを含む配列を返します。
たとえば、すべての10.000+メソッドの名前を一覧表示したい場合は、それを繰り返すことができます。
メソッド名が変更された場合、このようにtypeof(Program).GetMethod(nameof(Program.Main));
を実行することもできます。VisualStudioのリファクタリングによって、ここでも名前が変更されます。
注:「nameof」キーワードは、質問が投稿された5年前には利用できませんでした。
ここで手元の問題にいくつかの説明を付け加えましょう。指定されたメソッドに関する情報を返すメソッドGetMethodInfo(SomeMethodSymbol)
を探しています。メソッドはC#でオーバーロードされる可能性があるため、これは簡単ではありません。したがって、基本的には、追加の手がかりを呼び出しに提供して、コンパイラー(およびIntellisenseなどの他のコードアナライザー)がどのメソッドについて話しているのかを理解する必要があります。
たとえば、Math.Abs
メソッドに関する情報を探しているとします。次に、探しているメソッドのオーバーロードされたバージョンを正確に指定する必要があります。
// int
MethodInfo info1 = ((Func<int, int>)Math.Abs).Method;
// or double ?
MethodInfo info2 = ((Func<double, double>)Math.Abs).Method;
Math.Exp
メソッドのように既存のオーバーロードが1つしかない場合でも、メソッドが将来オーバーロードされてコードがコンパイルされなくなるため、タイピングの手がかりを提供する必要があります。
上記の発言を踏まえて、次の一連のヘルパーメソッドを提供して、すべてのメソッドをキャストしてその情報に到達するという面倒なタスクを多少軽減できます。
public static class GetMethodInfoUtil
{
// No cast necessary
public static MethodInfo GetMethodInfo(Action action) => action.Method;
public static MethodInfo GetMethodInfo<T>(Action<T> action) => action.Method;
public static MethodInfo GetMethodInfo<T,U>(Action<T,U> action) => action.Method;
public static MethodInfo GetMethodInfo<TResult>(Func<TResult> fun) => fun.Method;
public static MethodInfo GetMethodInfo<T, TResult>(Func<T, TResult> fun) => fun.Method;
public static MethodInfo GetMethodInfo<T, U, TResult>(Func<T, U, TResult> fun) => fun.Method;
// Cast necessary
public static MethodInfo GetMethodInfo(Delegate del) => del.Method;
}
次に、これらのヘルパーを次のように使用します。
var methodInfos = new[] {
// Static methods
GetMethodInfo<int, int>(Math.Abs),
GetMethodInfo<double, double>(Math.Abs),
GetMethodInfo<long, long, long>(Math.Max),
// Static void methods
GetMethodInfo(Console.Clear),
GetMethodInfo<string[]>(Main),
// With explicit cast if too many arguments
GetMethodInfo((Action<string, object, object>)Console.WriteLine),
// Instance methods
GetMethodInfo<string, bool>("".StartsWith),
GetMethodInfo(new List<int>().Clear),
};
Console.Clear
のような引数を取らないvoid静的メソッドを除いて、型情報は引き続き提供される必要があることに注意してください。また、インスタンスメソッドの場合、実際のインスタンスを使用して、より多くのリソースを使用する適切なメソッドを取得する必要があります。
さて、いくつかのコーナーケースでは、上記のヘルパーは機能しません。たとえば、メソッドがout
パラメータを使用するとします。これらの特殊なケースでは、ラムダ式からメソッド情報を抽出するのが便利になり、他のポスターによって提供されるソリューションに戻ります(コードインスピレーション here ):
public static class GetIndirectMethodInfoUtil
{
// Get MethodInfo from Lambda expressions
public static MethodInfo GetIndirectMethodInfo(Expression<Action> expression)
=> GetIndirectMethodInfo((LambdaExpression)expression);
public static MethodInfo GetIndirectMethodInfo<T>(Expression<Action<T>> expression)
=> GetIndirectMethodInfo((LambdaExpression)expression);
public static MethodInfo GetIndirectMethodInfo<T, TResult>(Expression<Func<TResult>> expression)
=> GetIndirectMethodInfo((LambdaExpression)expression);
public static MethodInfo GetIndirectMethodInfo<T, TResult>(Expression<Func<T, TResult>> expression)
=> GetIndirectMethodInfo((LambdaExpression)expression);
// Used by the above
private static MethodInfo GetIndirectMethodInfo(LambdaExpression expression)
{
if (!(expression.Body is MethodCallExpression methodCall))
{
throw new ArgumentException(
$"Invalid Expression ({expression.Body}). Expression should consist of a method call only.");
}
return methodCall.Method;
}
}
あなたはこのようなものを使うでしょう:
int dummyInt;
var moreMethodInfos = new[]
{
// Extracted from lambdas
GetIndirectMethodInfo(() => "".StartsWith("")),
GetIndirectMethodInfo((string s) => s.StartsWith(s)),
GetIndirectMethodInfo(() => int.TryParse("", out dummyInt)),
};
型情報は引き続き引数型から間接的に提供されることに注意してください。また、out
パラメータを使用できるようにするためだけに、ダミー引数が追加されていることに注意してください。
完全なデモプログラム: https://dotnetfiddle.net/CkS075 。
多分理想的な方法ではないかもしれませんが、それは役立つかもしれません:
var callback = typeof(BlogController).GetMethod(nameof(BlogController.GetBlogs));
これを支援するために必要なヘルパー関数を作成するT4テンプレートを作成しました。 Func <>またはAction <>メソッドからMethodInfoオブジェクトを取得する関数のリストを作成します。
次のコードをGetMethodInfo.tt
という名前のファイルにコピーします。
<#@ template language="C#" #>
<#@ output extension=".cs" encoding="utf-8" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Text" #>
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace Tools
{
public static class GetMethodInfo
{
<# int max = 12;
for(int i = 0; i <= max; i++)
{
var builder = new StringBuilder();
for(int j = 0; j <= i; j++)
{
builder.Append("T");
builder.Append(j);
if(j != i)
{
builder.Append(", ");
}
}
var T = builder.ToString();
#>
public static MethodInfo ForFunc<T, <#= T #>>(Expression<Func<T, <#= T #>>> expression)
{
var member = expression.Body as MethodCallExpression;
if (member != null)
return member.Method;
throw new ArgumentException("Expression is not a method", "expression");
}
public static MethodInfo ForAction<<#= T #>>(Expression<Action<<#= T #>>> expression)
{
var member = expression.Body as MethodCallExpression;
if (member != null)
return member.Method;
throw new ArgumentException("Expression is not a method", "expression");
}
<# } #>
}
}
メモ: