目的のオーバーロードされたジェネリック メソッドを参照する
-
09-09-2019 - |
質問
与えられた
public Class Example
{
public static void Foo< T>(int ID){}
public static void Foo< T,U>(int ID){}
}
質問:
- これを「オーバーロードされたジェネリック メソッド」と呼ぶのは正しいでしょうか?
MethodInfo オブジェクトの作成時にどちらかのメソッドを指定するにはどうすればよいですか?
Type exampleType = Type.GetType("fullyqualifiednameOfExample, namespaceOfExample"); MethodInfo mi = exampleType.GetMethod("Foo", BindingFlags.Public|BindingFlags.Static, null, new Type[] {typeof(Type), typeof(Type) }, null);
引数 4 はコンパイラに大きな不快感を与えます
解決
私はあなたが何をしたいだろうGetMethodを使用しての方法を見つけることができません。しかし、あなたはすべてのメソッドを取得し、あなたが欲しいの方法を見つけるまでリストを行くことができます。
あなたは、あなたが実際にそれを使用する前にMakeGenericMethodを呼び出す必要があります覚えています。
var allMethods = typeof (Example).GetMethods(BindingFlags.Public | BindingFlags.Static);
MethodInfo foundMi = allMethods.FirstOrDefault(
mi => mi.Name == "Foo" && mi.GetGenericArguments().Count() == 2);
if (foundMi != null)
{
MethodInfo closedMi = foundMi.MakeGenericMethod(new Type[] {typeof (int), typeof (string)});
Example example= new Example();
closedMi.Invoke(example, new object[] { 5 });
}
他のヒント
質問に対する回答と例を次に示します。
はい、ただし、ここでジェネリック メソッドに関して実際に注意すべき点が 2 つあります。それは、型推論とオーバーロード メソッドの解決です。型推論は、コンパイラがオーバーロードされたメソッド シグネチャを解決しようとする前に、コンパイル時に行われます。コンパイラは、同じ名前を共有するすべてのジェネリック メソッドに型推論ロジックを適用します。オーバーロード解決ステップでは、コンパイラには、型推論が成功したジェネリック メソッドのみが含まれます。 詳細はこちら...
以下の完全なコンソール アプリケーション プログラム コード例を参照してください。これは、MethodInfo オブジェクトの作成時に Foo メソッドのいくつかのバリアントを指定し、Extension メソッドを使用して呼び出す方法を示しています。
プログラム.cs
class Program
{
static void Main(string[] args)
{
MethodInfo foo1 = typeof(Example).GetGenericMethod("Foo",
new[] { typeof(string) },
new[] { typeof(int) },
typeof(void));
MethodInfo foo2 = typeof(Example).GetGenericMethod("Foo",
new[] { typeof(string), typeof(int) },
new[] { typeof(int) },
typeof(void));
MethodInfo foo3 = typeof(Example).GetGenericMethod("Foo",
new[] { typeof(string) },
new[] { typeof(string) },
typeof(void));
MethodInfo foo4 = typeof(Example).GetGenericMethod("Foo",
new[] { typeof(string), typeof(int) },
new[] { typeof(int), typeof(string) },
typeof(string));
Console.WriteLine(foo1.Invoke(null, new object[] { 1 }));
Console.WriteLine(foo2.Invoke(null, new object[] { 1 }));
Console.WriteLine(foo3.Invoke(null, new object[] { "s" }));
Console.WriteLine(foo4.Invoke(null, new object[] { 1, "s" }));
}
}
例.cs:
public class Example
{
public static void Foo<T>(int ID) { }
public static void Foo<T, U>(int ID) { }
public static void Foo<T>(string ID) { }
public static string Foo<T, U>(int intID, string ID) { return ID; }
}
拡張機能.cs:
public static class Extensions
{
public static MethodInfo GetGenericMethod(this Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)
{
MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
where m.Name == name &&
m.GetGenericArguments().Length == genericArgTypes.Length &&
m.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(argTypes) &&
m.ReturnType == returnType
select m).Single().MakeGenericMethod(genericArgTypes);
return foo1;
}
}
ベターます:
System.Linq.Enumerable.Select
の正しい過負荷を取得するための例の試み
private static MethodInfo GetMethod<T>(Expression<Func<T>> expression)
{
return ((MethodCallExpression)expression.Body).Method;
}
public static void CallSelect()
{
MethodInfo definition = GetMethod(() => Enumerable.Select(null, (Func<object, object>)null)).GetGenericMethodDefinition();
definition.MakeGenericMethod(typeof(int), typeof(int)).Invoke(null, new object[] { new List<int>(), ((Func<int, int>)(x => x)) });
}
ここにあなたが必要なもののためのLINQのワンライナーは、次のとおりです。
MethodInfo mi = exampleType.GetMethods().First(m=>m.GetGenericArguments().Length == 2);
私はあなたのラムダクエリの少しの修正を行います。
ジェネリックパラメータの型のSiはあなたがそのようなことをしなければならないときます:
私はpi.ParameterType.GetGenericTypeDefinition()
を追加します。
と
(m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)
このように、方法は、非常に細かい作業
MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
where m.Name == name
&& m.GetGenericArguments().Length == genericArgTypes.Length
&& m.GetParameters().Select(pi => pi.ParameterType.IsGenericType ? pi.ParameterType.GetGenericTypeDefinition() : pi.ParameterType).SequenceEqual(argTypes) &&
(returnType==null || (m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)
select m).FirstOrDefault();
if (foo1 != null)
{
return foo1.MakeGenericMethod(genericArgTypes);
}
return null;
例:
私が呼び出すことができる方法の変更で この拡張メソッド
public static IQueryable<T> FilterCulture<T>(this Table<T> t, IDatabaseFilter filter)
このような私の新しいヘルパーと
var QueryableExpression = MethodInfoHelper.GetGenericMethod(typeof(LinqFilterExtension), "FilterCulture", new Type[] { rowType }, new Type[] { typeof(Table<>), typeof(IDatabaseFilter) }, typeof(IQueryable<>));
私のヘルパーの署名がある。
public static MethodInfo GetGenericMethod(Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)