简体   繁体   中英

Pass generic type parameter to Func

I have a couple of function like CallMyFunction in my codebase. I would like to refactor them into one generic function

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 be able to have something like

//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);

I would simply create a dictionary of myenum/action pairs

Your dictionary:

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

calling a method

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

In your example, there are no parameters for any calls to MyFunction<> , meaning there are no generic arguments required for Action . Likewise, you cannot change to CallMyFunction<T> as T changes depending on the enum .

As for <A> , <B> and <C> , these have to be specified in each case rather than put in as part of a generic argument to Action . The switch is calling the methods, not the caller of GenericCall . It's this key point that you're working around, to dynamically select <A> , <B> and <C> based on the enum value.

Trying to put an argument into CallMyFunction for myFunc effectively means the caller has to supply the types A , B and C which negates the purpose of the switch . This isn't what you're trying to do I think.

One way of refactoring would be to change the method MyFunction<T> to take the type parameter as a parameter rather than a generic. This would allow you to do the following;

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);
}

However this doesn't really save you anything.

To get proper value out of it, you could create a custom Attribute that took a constructor argument of Type and apply the Attribute directly to the enum . Your function MyFunction , could be modified to check for the Attribute on the enum and correctly pass the correct type to MyFunction .

That said, it'd only be worth it if you had a large (>10) enum values/types. The structure as it stands is fairly straight forward and easy (if mundane), to maintain.

It's worth mentioning that you could also use reflection to call MyFunction<> and supply the generic argument at runtime but you'd still be left with picking out the type by enum . It would add more code to maintain rather than reduce it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM