1

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);
Bruno
  • 623
  • 2
  • 9
  • 24

2 Answers2

2

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]();
}
Eser
  • 12,346
  • 1
  • 22
  • 32
0

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.

DiskJunky
  • 4,750
  • 3
  • 37
  • 66