【问题标题】:Generic type passing and usage, can I do the following?泛型类型传递和使用,我可以做以下吗?
【发布时间】:2012-12-09 00:55:15
【问题描述】:

我试图弄清楚如何访问 CallMe<T>()DoSomething 中的静态方法。反射是这里唯一的解决方案吗?我不想实例化MyAction 类型的对象。此外,如果通过反射进行,是否有一种方法可以通过方法CallMe<T>() 中的反射创建该方法一次,然后多次调用它以对同一个“反射”方法执行多个操作?或者有什么比通过反射更好的方法吗?我基本上想创建模板实现样式类,例如 MyAction 来定义 byte[] DoThis(string text) 如何执行其职责。然后AskForSomething() 将指定正在使用的模板,并据此CallMe<T>() 将开始其工作。

    public class AskSomething
    {
        public void AskForSomething()
        {
            DoSomething doSomething = new DoSomething();
            doSomething.CallMe<MyAction>();
        }
    }

    public class DoSomething
    {
        public void CallMe<T>()
        {
            Type type = typeof(T);

            //Question: How can I access 'DoThis(string text)' here?
            //Most likely by reflection? 
        }
    }

    public class MyAction
    {
        public static byte[] DoThis(string text)
        {
            byte[] ret = new byte[0]; //mock just to denote something is done and out comes a byte array

            return ret;
        }
    }

【问题讨论】:

    标签: c# generics reflection interface


    【解决方案1】:
      public class DoSomething
      {
        class Cache<T>
        {
          public readonly static Func<string, byte[]> action = (Func<string, byte[]>)Delegate.CreateDelegate(typeof(Func<string, byte[]>), typeof(T).GetMethod("DoThis"));
        }
        public void CallMe<T>()
        {
          Cache<T>.action("text");
        }
      }
    

    【讨论】:

    • 技术上正确,当然不可能维护和设计:)
    • @KierenJohnstone 我们不是在寻找简单的方法
    • 什么?是的,所有软件开发人员都应该始终寻找一种简单的方法。你可以用剪刀敲钉子——有人甚至会问,用什么剪刀敲钉子最好——当然,每次你都应该用锤子..
    • @DarkGray,虽然接口解决方案在这种情况下看起来更合适,但您是否介意解释一下您的解决方案将如何工作,以防我决定将来使用反射(我对编程很陌生)。我现在如何在迭代一百万次的循环中调用这个调用的方法,而不必在每次迭代时再次调用该方法?我想我已经在最初的问题中提出了这一点。
    • @DarkGray,老实说,鉴于方法调用是在循环中完成的,我看不出您的答案如何避免在每次迭代中一次又一次地调用。并且不确定您是否只是在假期前搞砸了……奇怪的是,您坚持认为这是比界面更好的解决方案……无论如何,谢谢!
    【解决方案2】:

    基于“DoThis”不必是静态的这一事实,您可以通过以下方式实现这一点:-

    using System;
    
    namespace ConsoleApplication3
    {
    class Program
    {
        static void Main(string[] args)
        {
            DoSomething doSomething = new DoSomething();
            doSomething.CallMe<MyAction>();
    
        }
    }
    public class DoSomething
    {
        public void CallMe<T>() where T : IMyAction
        {
           IMyAction action =  (IMyAction)Activator.CreateInstance(typeof(T));
    
           var result = action.DoThis("value");            
        }
    }
    
    public interface IMyAction
    {
        byte[] DoThis(string text);
    }
    
    public class MyAction : IMyAction
    {
        public byte[] DoThis(string text)
        {
            byte[] ret = new byte[0]; //mock just to denote something is done and out comes a byte array
    
            return ret;
        }
    }
    }
    

    我不确定我是否会推荐这种方法,但它确实有效! (例如,如果没有默认构造函数,这将失败)。

    【讨论】:

    • 这是一种反射方式吗?顺便说一句,我认为您需要致电 doSomething.CallMe&lt;MyAction&gt;() 而不是 doSomething.CallMe(),对吗?
    • 是的,Activator.CreateInstance 是有效的反射。如果有意义,您可以多次使用它(但请记住方法 CallMe 可以使用与上一次调用不同的类型调用)
    • 当然,否则我想如果不打算让 T 成为实现 IMyAction 的不同类型,那么这个问题将没有实际意义。感谢您指出。
    【解决方案3】:

    如果您的 DoThis 方法需要是静态的,您也可以将您的 CallMe 方法更改为以下内容:

    public void CallMe(Func<string, byte[]> action)
    {
        byte[] result = action("input");
    }
    

    现在您可以将函数的引用传递给CallMe 方法,如下所示:

     doSomething.CallMe(MyAction.DoThis);
    

    【讨论】:

    • 这类似于委托还是委托?
    • 是的,这是一个代表。您可以使用此委托来表示可以作为参数传递的方法,而无需显式声明自定义委托(请参阅Func<T, TResult> Delegate
    • 感谢您的解释,您是否偶然知道委托和接口实现之间的性能差异是什么?我记得在 SO 上遇到过类似的问题,但我再也找不到了。
    • 这里是讨论 interfaces vs delegates 的 stackoverflow 问题,但在担心性能之前,先读一读:Which is faster?
    • 谢谢这正是我之前遇到的,如果性能确实是一个问题,也感谢我自己对性能分析的建议(在这里,我每秒处理大约 15-20 百万个项目,所以即使微秒领域的差异加起来。)。
    【解决方案4】:

    DoThis定义一个接口,让MyAction实现它,并用where T : IMyInterfaceT类型参数约束为它的一个实例

    【讨论】:

    • +1 我试图解释为什么这不起作用,但描述如何使它起作用显然要简单得多......
    • 接口是执行此操作的正确方法,但如果您必须将 DoThis 作为静态方法,那么您将不得不使用反射。
    • @KierenJohnstone,好的,所以界面似乎是要走的路。但我认为这意味着我必须传入一个 T 实例,对吗?
    • @RossDargan,DoThis 不一定是静态的。我只想绕过必须传入 MyAction 类的实例。我所需要的只是访问 DoThis 方法。
    • new T().DoThis("abc"),或者确实可以传入一个实例。您需要使用 where T : IMyInterface, new() 进行约束,以确保它具有无参数构造函数
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-27
    • 1970-01-01
    • 2011-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多