C# 如何使用反射调用泛型方法?

C# 如何使用反射调用泛型方法?,c#,.net,generics,reflection,C#,.net,Generics,Reflection,当类型参数在编译时未知,但在运行时动态获取时,调用泛型方法的最佳方法是什么 考虑以下示例代码-在Example()方法中,使用myType变量中存储的Type调用GenericMethod()最简洁的方法是什么 public class Sample { public void Example(string typeName) { Type myType = FindType(typeName); // What goes here to cal

当类型参数在编译时未知,但在运行时动态获取时,调用泛型方法的最佳方法是什么

考虑以下示例代码-在
Example()
方法中,使用
myType
变量中存储的
Type
调用
GenericMethod()
最简洁的方法是什么

public class Sample
{
    public void Example(string typeName)
    {
        Type myType = FindType(typeName);

        // What goes here to call GenericMethod<T>()?
        GenericMethod<myType>(); // This doesn't work

        // What changes to call StaticMethod<T>()?
        Sample.StaticMethod<myType>(); // This also doesn't work
    }

    public void GenericMethod<T>()
    {
        // ...
    }

    public static void StaticMethod<T>()
    {
        //...
    }
}
公共类示例
{
公共void示例(字符串类型名)
{
类型myType=FindType(类型名称);
//这里调用GenericMethod()的是什么?
GenericMethod();//这不起作用
//调用StaticMethod()有什么变化?
Sample.StaticMethod();//这也不起作用
}
public-void-GenericMethod()
{
// ...
}
公共静态void StaticMethod()
{
//...
}
}

您需要使用反射来获取要开始使用的方法,然后通过提供以下类型参数来“构造”它:

对于静态方法,将
null
作为第一个参数传递给
Invoke
。这与泛型方法无关——它只是普通的反射


如前所述,对于C#4来说,使用
动态
,这一点要简单得多——当然,如果可以使用类型推断的话。在类型推断不可用的情况下,例如问题中的确切示例,它没有帮助。

您需要使用反射来获取要开始的方法,然后通过提供以下类型参数来“构造”它:

对于静态方法,将
null
作为第一个参数传递给
Invoke
。这与泛型方法无关——它只是普通的反射


如前所述,对于C#4来说,使用
动态
,这一点要简单得多——当然,如果可以使用类型推断的话。在类型推断不可用的情况下,例如问题中的确切示例,它没有帮助。

只是对原始答案的补充。虽然这将起作用:

MethodInfo method = typeof(Sample).GetMethod("GenericMethod");
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);
这也有点危险,因为您丢失了对
GenericMethod
的编译时检查。如果以后执行重构并重命名
GenericMethod
,则此代码不会注意到,并且在运行时会失败。此外,如果程序集有任何后期处理(例如混淆或删除未使用的方法/类),此代码也可能会中断

因此,如果您知道您在编译时链接到的方法,并且该方法没有被调用数百万次,因此开销无关紧要,那么我会将此代码更改为:

Action<> GenMethod = GenericMethod<int>;  //change int by any base type 
                                          //accepted by GenericMethod
MethodInfo method = this.GetType().GetMethod(GenMethod.Method.Name);
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);
Action GenMethod=GenericMethod//按任意基类型更改int
//一般方法接受
MethodInfo method=this.GetType().GetMethod(GenMethod.method.Name);
MethodInfo generic=method.MakeGenericMethod(myType);
generic.Invoke(this,null);
虽然不是很漂亮,但这里有一个对
GenericMethod
的编译时引用,如果您重构、删除或使用
GenericMethod
执行任何操作,此代码将继续工作,或者至少在编译时中断(例如,如果您删除
GenericMethod


另一种方法是创建一个新的包装类,并通过
Activator
创建它。我不知道是否有更好的方法。

只是对原始答案的补充。虽然这将起作用:

MethodInfo method = typeof(Sample).GetMethod("GenericMethod");
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);
这也有点危险,因为您丢失了对
GenericMethod
的编译时检查。如果以后执行重构并重命名
GenericMethod
,则此代码不会注意到,并且在运行时会失败。此外,如果程序集有任何后期处理(例如混淆或删除未使用的方法/类),此代码也可能会中断

因此,如果您知道您在编译时链接到的方法,并且该方法没有被调用数百万次,因此开销无关紧要,那么我会将此代码更改为:

Action<> GenMethod = GenericMethod<int>;  //change int by any base type 
                                          //accepted by GenericMethod
MethodInfo method = this.GetType().GetMethod(GenMethod.Method.Name);
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);
Action GenMethod=GenericMethod//按任意基类型更改int
//一般方法接受
MethodInfo method=this.GetType().GetMethod(GenMethod.method.Name);
MethodInfo generic=method.MakeGenericMethod(myType);
generic.Invoke(this,null);
虽然不是很漂亮,但这里有一个对
GenericMethod
的编译时引用,如果您重构、删除或使用
GenericMethod
执行任何操作,此代码将继续工作,或者至少在编译时中断(例如,如果您删除
GenericMethod

另一种方法是创建一个新的包装类,并通过
Activator
创建它。我不知道是否有更好的方法。

对于C#4.0,反射是不必要的,因为DLR可以使用运行时类型来调用它。由于动态地使用DLR库是一种痛苦(而不是C#编译器为您生成代码),开放源代码框架(.net standard 1.5)使您能够轻松地缓存运行时访问编译器将为您生成的相同调用

var name = InvokeMemberName.Create;
Dynamic.InvokeMemberAction(this, name("GenericMethod", new[]{myType}));


var staticContext = InvokeContext.CreateStatic;
Dynamic.InvokeMemberAction(staticContext(typeof(Sample)), name("StaticMethod", new[]{myType}));
对于C#4.0,反射是不必要的,因为DLR可以使用运行时类型来调用反射。由于动态地使用DLR库是一种痛苦(而不是C#编译器为您生成代码),开放源代码框架(.net standard 1.5)使您能够轻松地缓存运行时访问编译器将为您生成的相同调用

var name = InvokeMemberName.Create;
Dynamic.InvokeMemberAction(this, name("GenericMethod", new[]{myType}));


var staticContext = InvokeContext.CreateStatic;
Dynamic.InvokeMemberAction(staticContext(typeof(Sample)), name("StaticMethod", new[]{myType}));

通过使用类型而不是反射API,使用仅在运行时才知道的类型参数调用泛型方法可以大大简化

要使用此技术,必须从实际对象(而不仅仅是
类型
类的实例)知道类型。否则,必须创建该类型的对象或使用标准反射API。可以使用该方法创建对象

如果您想调用一个泛型方法,在“正常”用法中,该方法会推断出其类型,那么它只需将未知类型的对象强制转换为
动态
。下面是一个例子:

class Alpha { }
class Beta { }
class Service
{
    public void Process<T>(T item)
    {
        Console.WriteLine("item.GetType(): " + item.GetType()
                          + "\ttypeof(T): " + typeof(T));
    }
}

class Program
{
    static void Main(string[] args)
    {
        var a = new Alpha();
        var b = new Beta();

        var service = new Service();
        service.Process(a); // Same as "service.Process<Alpha>(a)"
        service.Process(b); // Same as "service.Process<Beta>(b)"

        var objects = new object[] { a, b };
        foreach (var o in objects)
        {
            service.Process(o); // Same as "service.Process<object>(o)"
        }
        foreach (var o in objects)
        {
            dynamic dynObj = o;
            service.Process(dynObj); // Or write "service.Process((dynamic)o)"
        }
    }
}
过程
是一个通用实例
class Program
{
    static void Main(string[] args)
    {
        object obj = new Alpha();

        Helper((dynamic)obj);
    }

    public static void Helper<T>(T obj)
    {
        GenericMethod<T>();
    }

    public static void GenericMethod<T>()
    {
        Console.WriteLine("GenericMethod<" + typeof(T) + ">");
    }
}
interface IItem { }
class FooItem : IItem { }
class BarItem : IItem { }
class Alpha { }

class Program
{
    static void Main(string[] args)
    {
        var objects = new object[] { new FooItem(), new BarItem(), new Alpha() };
        for (int i = 0; i < objects.Length; i++)
        {
            ProcessItem((dynamic)objects[i], "test" + i, i);

            //ProcesItm((dynamic)objects[i], "test" + i, i);
            //compiler error: The name 'ProcesItm' does not
            //exist in the current context

            //ProcessItem((dynamic)objects[i], "test" + i);
            //error: No overload for method 'ProcessItem' takes 2 arguments
        }
    }

    static string ProcessItem<T>(T item, string text, int number)
        where T : IItem
    {
        Console.WriteLine("Generic ProcessItem<{0}>, text {1}, number:{2}",
                          typeof(T), text, number);
        return "OK";
    }
    static void ProcessItem(BarItem item, string text, int number)
    {
        Console.WriteLine("ProcessItem with Bar, " + text + ", " + number);
    }
}
var result = ProcessItem((dynamic)testObjects[i], "test" + i, i);
string result = ProcessItem((dynamic)testObjects[i], "test" + i, i);
((Action)GenericMethod<object>)
    .Method
    .GetGenericMethodDefinition()
    .MakeGenericMethod(typeof(string))
    .Invoke(this, null);
MethodInfo method = typeof(Sample).GetMethod("GenericMethod");
MethodInfo method = ((Action)GenericMethod<object>)
    .Method
    .GetGenericMethodDefinition();

MethodInfo method = ((Action)StaticMethod<object>)
    .Method
    .GetGenericMethodDefinition();
MethodInfo method = ((Action)(new Sample())
    .GenericMethod<object>)
    .Method
    .GetGenericMethodDefinition();

MethodInfo method = ((Action)Sample.StaticMethod<object>)
    .Method
    .GetGenericMethodDefinition();
MethodInfo method = ((MethodCallExpression)((Expression<Action<Sample>>)(
    (Sample v) => v.GenericMethod<object>()
    )).Body).Method.GetGenericMethodDefinition();
Expression<Action<Sample>> expr = (Sample v) => v.GenericMethod<object>();
MethodCallExpression methodCallExpr = (MethodCallExpression)expr.Body;
MethodInfo methodA = methodCallExpr.Method.GetGenericMethodDefinition();
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);
public class Helpers
{
    public static U ConvertCsvDataToCollection<U, T>(string csvData)
    where U : ObservableCollection<T>
    {
      //transform code here
    }
}
object myCollection = Activator.CreateInstance(collectionType);
object myoObject = Activator.CreateInstance(objectType);
MethodInfo method = typeof(Helpers).
GetMethod("ConvertCsvDataToCollection");
MethodInfo generic = method.MakeGenericMethod(
new Type[] {
   myCollection.GetType(),
   myObject.GetType()
});
generic.Invoke(null, new object[] { csvData });
object myCollection = null;

MethodInfo method = typeof(Helpers).
GetMethod("ConvertCsvDataToCollection");

MethodInfo generic = method.MakeGenericMethod(
   myClassInfo.CollectionType,
   myClassInfo.ObjectType
);

myCollection = generic.Invoke(null, new object[] { csvData });
using System;
using System.Collections;
using System.Collections.Generic;

namespace DictionaryRuntime
{
    public class DynamicDictionaryFactory
    {
        /// <summary>
        /// Factory to create dynamically a generic Dictionary.
        /// </summary>
        public IDictionary CreateDynamicGenericInstance(Type keyType, Type valueType)
        {
            //Creating the Dictionary.
            Type typeDict = typeof(Dictionary<,>);

            //Creating KeyValue Type for Dictionary.
            Type[] typeArgs = { keyType, valueType };

            //Passing the Type and create Dictionary Type.
            Type genericType = typeDict.MakeGenericType(typeArgs);

            //Creating Instance for Dictionary<K,T>.
            IDictionary d = Activator.CreateInstance(genericType) as IDictionary;

            return d;

        }
    }
}
using System;
using System.Collections.Generic;

namespace DynamicDictionary
{
    class Test
    {
        static void Main(string[] args)
        {
            var factory = new DictionaryRuntime.DynamicDictionaryFactory();
            var dict = factory.CreateDynamicGenericInstance(typeof(String), typeof(int));

            var typedDict = dict as Dictionary<String, int>;

            if (typedDict != null)
            {
                Console.WriteLine("Dictionary<String, int>");

                typedDict.Add("One", 1);
                typedDict.Add("Two", 2);
                typedDict.Add("Three", 3);

                foreach(var kvp in typedDict)
                {
                    Console.WriteLine("\"" + kvp.Key + "\": " + kvp.Value);
                }
            }
            else
                Console.WriteLine("null");
        }
    }
}
Dictionary<String, int>
"One": 1
"Two": 2
"Three": 3
public class Bar { }
public class Square { }
public class myClass
{
    public void Foo<T>(T item)
    {
        Console.WriteLine(typeof(T).Name);
    }
}
public static class Extension
{
    public static void InvokeFoo<T>(this T t)
    {
        var fooMethod = typeof(myClass).GetMethod("Foo");
        var tType = typeof(T);
        var fooTMethod = fooMethod.MakeGenericMethod(new[] { tType });
        fooTMethod.Invoke(new myClass(), new object[] { t });
    }
}
var objSquare = new Square();
objSquare.InvokeFoo();

var objBar = new Bar();
objBar.InvokeFoo();