如何通过反射调用类中的<泛型>方法

来源:互联网 发布:北京朝阳教育网络视频 编辑:程序博客网 时间:2024/05/29 15:50

定义的接口:

namespace IProgramShut{    public interface IShut    {        /// <summary>        /// 操作名称        /// </summary>        string OperatorName        {            get;        }        /// <summary>        /// 操作方法        /// </summary>        /// <typeparam name="T"></typeparam>        /// <typeparam name="TResult"></typeparam>        /// <param name="t"></param>        /// <returns></returns>        TResult Operator<T, TResult>(T t);    }}

派生自接口的派生类:

namespace ProgramShutDown{    public class ProgramShutDown  :IShut    {        /// <summary>        /// 显示“关机”字样        /// </summary>        public string OperatorName        {            get            {                return "关机";            }        }        /// <summary>        /// 关机操作        /// </summary>        /// <typeparam name="T"></typeparam>        /// <typeparam name="TResult"></typeparam>        /// <param name="t"></param>        /// <returns></returns>        public TResult Operator<T,TResult>(T t)        {            this.ShutDown(t.ToString());            return default(TResult);        }        /// <summary>        /// 执行关机        /// </summary>        /// <param name="second"></param>        public void ShutDown(string second)        {            Process process = new Process();            try            {                process.StartInfo.FileName = "cmd.exe";                process.StartInfo.UseShellExecute = false;                process.StartInfo.RedirectStandardInput = true;                process.StartInfo.RedirectStandardOutput = true;                process.StartInfo.RedirectStandardError = true;                process.StartInfo.CreateNoWindow = true;                process.Start();                process.StandardInput.WriteLine("shutdown -s -f -t " + second);                process.StandardInput.WriteLine("exit");            }            catch (Exception ex)            {            }            finally            {                process.Close();                process.Dispose();                process = null;            }        }    }}

具体的调用方法:

   Type t = tsi.Tag as Type;   //1、获取指定方法名称的泛型方法   MethodInfo mi = t.GetMethod("Operator");   //2、创建一个对应泛型类型的非泛型反射方法   MethodInfo mi2 = mi.MakeGenericMethod(new Type[] { typeof(int), typeof(int) });   object o = Activator.CreateInstance(t);   mi2.Invoke(o, new object[] { 3000 });


其中tsi是一个ToolStripItem对象,

我把通过反射获取到的需要被调用的类的类型存在了ToolStripItem.Tag中了,

 MethodInfo mi =t.GetMethod("Operator")通过方法名称获取到泛型方法的版本,

然后在获取到的泛型方法MethodInfo mi的基础上,

通过mi的MakeGenericMethod(new Type[] { typeof(int), typeof(int) })方法,创建一个非泛型版本,

其中

new Type[] { typeof(int), typeof(int)}是用来替换泛型类型 T,TResult的具体类型,

其中

泛型方法在接口中的声明如下:

TResult Operator<T, TResult>(T t);


MethodInfo 类中的 MakeGenericMethod方法在NET中定义如下

        //        // 摘要:        //     用类型数组的元素替代当前泛型方法定义的类型参数,并返回表示结果构造方法的 System.Reflection.MethodInfo 对象。        //        // 参数:        //   typeArguments:        //     要替换当前泛型方法定义的类型参数的类型数组。        //        // 返回结果:        //     一个 System.Reflection.MethodInfo 对象,表示通过将当前泛型方法定义的类型参数替换为 typeArguments 的元素生成的构造方法。        //        // 异常:        //   System.InvalidOperationException:        //     当前 System.Reflection.MethodInfo 不表示泛型方法定义。 也就是说,System.Reflection.MethodInfo.IsGenericMethodDefinition        //     返回 false。        //        //   System.ArgumentNullException:        //     typeArguments 为 null。 - 或 - typeArguments 的所有元素均为 null。        //        //   System.ArgumentException:        //     typeArguments 中元素的数目与当前泛型方法定义的类型参数的数目不同。 - 或 - typeArguments 的某个元素不满足为当前泛型方法定义的相应类型参数指定的约束。        //        //   System.NotSupportedException:        //     不支持此方法。        public virtual MethodInfo MakeGenericMethod(params Type[] typeArguments);


第一次尝试的时候是通过mi.Invoke直接调用的爆出了异常:

无法绑定到目标方法,因其签名或安全透明度与委托类型的签名或安全透明度不兼容。

后来查资料再是尝试,找到了另外的调用方式。做个记录。


再说一句:

在这个例子中,想要调用的方法刚好是从接口中继承来的,public类型的方法,

在通过反射调用泛型方法的时候已经获取到了对应类型的实例对象,

原本可以直接通过实例对象调用对应的方法,

但是不排除将来在实际使用的时候想要调用的是private方法,

或者是派生类中特有的定义的方法,这个例子只是凑巧了。



另外做个标记:


通过反射获取泛型类型的具体类型的方法是通过:

Type类的MakeGenericType方法来获取

该方法在NET中的定义如下

        //        // 摘要:        //     替代由当前泛型类型定义的类型参数组成的类型数组的元素,并返回表示结果构造类型的 System.Type 对象。        //        // 参数:        //   typeArguments:        //     将代替当前泛型类型的类型参数的类型数组。        //        // 返回结果:        //     System.Type 表示的构造类型通过以下方式形成:用 typeArguments 的元素取代当前泛型类型的类型参数。        //        // 异常:        //   System.InvalidOperationException:        //     当前类型不表示泛型类型定义。 即,System.Type.IsGenericTypeDefinition 返回 false。        //        //   System.ArgumentNullException:        //     typeArguments 为 null。 - 或 - typeArguments 的所有元素均为 null。        //        //   System.ArgumentException:        //     typeArguments 中元素的个数不等于当前泛型类型定义中类型参数的个数。 - 或 - typeArguments 的所有元素都不满足为当前泛型类型的对应类型参数指定的约束。        //     - 或 - typeArguments包含元素,它是一个指针类型 (System.Type.IsPointer返回true),by-ref 类型        //     (System.Type.IsByRef返回true),或 System.Void。        //        //   System.NotSupportedException:        //     基类不支持所调用的方法。 派生类必须提供实现。        public virtual Type MakeGenericType(params Type[] typeArguments);



调用方式和MathodInfo的对应方法调用方式一样,需要传递指定的具体类型的数组:


  Type t = tsi.Tag as Type;  t.MakeGenericType(new object[]{typeof(int),typeof(string),..,..,..})    ;



0 0
原创粉丝点击