【问题标题】:Pass generic type parameter to Func将泛型类型参数传递给 Func
【发布时间】:2017-11-01 19:12:44
【问题描述】:

我的代码库中有几个函数,例如 CallMyFunction。我想将它们重构为一个通用函数

enum MyEnum
{
    ValueA,
    ValueB,
    ValueC
}

static void MyFunction<T>()
{
    //...
}

static void CallMyFunction(MyEnum myEnum)
{
    switch (myEnum)
    {
        case MyEnum.ValueA:
            MyFunction<A>();
            break;
        case MyEnum.ValueB:
            MyFunction<B>();
            break;
        case MyEnum.ValueC:
            MyFunction<C>();
            break;                                                              
    }
}

我希望能够拥有类似的东西

//I would like to make it work for Func<T> too
static void GenericCall(MyEnum myEnum, Action<?????> myFunc) 
{
    switch (myEnum)
    {
        case MyEnum.ValueA:
            myFunc<A>();
            break;
        case MyEnum.ValueB:
            myFunc<B>();
            break;
        case MyEnum.ValueC:
            myFunc<C>();
            break;                                                              
    }
}

//And then call it like this
GenericCall(myEnum, MyFunction);
GenericCall(myEnum, AnotherFunction);

【问题讨论】:

    标签: c# generics func


    【解决方案1】:

    我会简单地创建一个 myenum/action 对的字典

    你的字典:

    Dictionary<MyEnum,Action> actions = new Dictionary<MyEnum,Action>()
    {
        {ValueA, ()=>{your code...}},
        {ValueB, ()=>{your code...}}
    };
    

    调用方法

    static void CallMyFunction(MyEnum myEnum)
    {
        actions[myEnum]();
    }
    

    【讨论】:

    • 根据以下:stackoverflow.com/questions/11617091/…,这可能会影响性能。
    • @KOTIX 如果您有数百万个案例需要切换,我同意。
    • @KOTIX,您还会有 lambda 的性能开销。如果您对性能开销感到满意,这是一种相当干净的方法。
    • @DiskJunky lamda 查询只是在编译时确定的函数调用。不是什么大话题。 x=&gt;x==1 正好等于 delegate(int i){ return x==1;}
    • @Bruno 问题是你的,是否使用这篇文章,但你在之前评论中的所有论点都是无效的(关于安全性、代码重复等。我认为你对这个答案的理解不够)
    【解决方案2】:

    在您的示例中,对MyFunction&lt;&gt; 的任何调用都没有参数,这意味着Action 不需要通用参数。同样,您不能更改为CallMyFunction&lt;T&gt;,因为T 会根据enum 而更改。

    对于&lt;A&gt;&lt;B&gt;&lt;C&gt;,它们必须在每个case 中指定,而不是作为Action 的通用参数的一部分。 switch 正在调用方法,而不是 GenericCall 的调用者。这是您正在解决的关键点,即根据enum 值动态选择&lt;A&gt;&lt;B&gt;&lt;C&gt;

    尝试将参数放入CallMyFunction for myFunc 实际上意味着调用者必须提供类型ABC,这否定了switch 的目的。我认为这不是你想要做的。

    重构的一种方法是更改​​方法MyFunction&lt;T&gt; 以将类型参数作为参数而不是泛型。这将允许您执行以下操作;

    enum MyEnum
    {
        ValueA,
        ValueB,
        ValueC
    }
    
    static void MyFunction(Type type)
    {
        //...
    }
    
    static void CallMyFunction(MyEnum myEnum)
    {
        Type type;
        switch (myEnum)
        {
            case MyEnum.ValueA:
                type = typeof(A);
                break;
            case MyEnum.ValueB:
                type = typeof(B);
                break;
            case MyEnum.ValueC:
                type = typeof(C);
                break;                                                              
        }
        MyFunction(type);
    }
    

    但是这并不能真正为您节省任何东西。

    要从中获得适当的价值,您可以创建一个自定义Attribute,它采用Type 的构造函数参数并将Attribute 直接应用于enum。你的函数MyFunction,可以修改为检查枚举上的Attribute,并正确地将正确的类型传递给MyFunction

    也就是说,只有当你有一个大的 (>10) enum 值/类型时,它才值得。目前的结构相当简单且易于维护(如果是普通的话)。

    值得一提的是,您还可以使用反射来调用 MyFunction&lt;&gt; 并在运行时提供泛型参数,但您仍然需要通过 enum 选择类型。它将添加更多代码来维护而不是减少它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-12
      • 1970-01-01
      • 2010-11-15
      • 1970-01-01
      相关资源
      最近更新 更多