0

I have a dictionary that contains an enum (key) and a method (value). All of the methods do something different; some of them use parameters and some of them don't. In order to store all methods in one dictionary, I've decided to use a struct as the sole parameter for each method. The parameters that the methods will use are all different (ie. some may need a range (int min, int max), or a string (string format)). What's the cleanest way to do this? Right now I have a couple parameters of each type to be used at will, and leave it up to the method caller and method to coordinate the correct usage. It's an ugly way to do things and usually if it's ugly there's a cleaner way. Looking for some input from folks who have done something similar!

Dictionary<Enums.MethodTypes, Func<MethodArguments, string>> 
     methodDictionary = new Dictionary<Enums.MethodTypes, Func<MethodArguments, string>

public struct MethodArguments
{
    int intArg_1;
    int intArg2_2;

    string strArg_1;
    string strArg_2;

    double dblArg_1;
    double dblArg_2;

    public MethodArguments(int a1, int a2, string s1, string s2, double d1, double d2)
    {
        intArg_1 = a1;
        intArg_2 = a2;
        strArg_1 = s1;
        strArg_2 = s2;
        dblArg_1 = d1;
        dblArg_2 = d2;
    }
}

The big picture:

First and foremost, I just learned of the idea of a dictionary of functions and I'd love to use it, I think that's pretty cool. Based on user input that is linked to an enum, we execute the appropriate method. I would like to go this route (if it's possible) for reasons stated above, and to avoid a really large switch statement.

Talen Kylon
  • 1,908
  • 7
  • 32
  • 60
  • Don't use mutable `struct`s. – SLaks May 01 '17 at 21:10
  • 2
    @SLaks to be fair, there's nothing there that would mutate it or allow it to be externally mutated – Marc Gravell May 01 '17 at 21:11
  • 1
    Why do you want to store each Func in a Dictionary? What's the original problem? – Francesco Bonizzi May 01 '17 at 21:20
  • @FrancescoB. I've included a quick summary of the big picture and why I've chosen to store each Func in a dictionary. I hope that answers your question. – Talen Kylon May 01 '17 at 21:26
  • 1
    If your parameters aren't uniform, you shouldn't do that. – SLaks May 01 '17 at 21:38
  • As you did, the large switch is transposed in the method that consumes MethodArguments. You could avoid using a switch statement in this way only if you have the the same parameters for each function. – Francesco Bonizzi May 01 '17 at 21:39
  • "pretty cool" isn't a very strong argument when it comes to robust software design (enthusiasm can be convincing sometimes though :)) Anyway, who or what will be responsible for gathering the input parameters? – C.Evenhuis May 01 '17 at 21:41
  • @C.Evenhuis Point taken on the "pretty cool" argument. Parameters would be taken from the UI and the struct would be shipped off to a Controller that would get the correct method and pass on the struct. – Talen Kylon May 01 '17 at 21:47
  • @SLaks I appreciate your feedback. If you could elaborate more on what I shouldn't do and why, and maybe even alternative approaches that would be awesome. Thanks again. – Talen Kylon May 01 '17 at 21:51
  • 1
    The `struct` you're proposing is awful. For each method signature, you're going to add more fields to the `struct`, making it grow in size to ridiculous degree. Even if you change it to effectively union the different signatures (i.e. using `[FieldOffset]`), it's still a maintenance nightmare. See marked duplicates for better options. Short version: use base type `Delegate` as the value. At the call site, you'll either know at compile time the signature or not; if so, just include a compile-time cast to the right delegate type. If not, put the arguments in an array and call `DynamicInvoke()`. – Peter Duniho May 01 '17 at 23:53

1 Answers1

0

If you're getting the parameters from the user interface, you'll probably start off with a string[]. Something would then need to decide to what type to convert the argument and where to put it (intArg_1 or strArg_1). And since the methods themselves don't expose that information, you'd need to store that information somewhere, too.

If you'd allow a bit of reflection (and if this input directly from the user, the performance hit won't be noticeable) you will probably have simpler code storing MethodInfos in your dictionary. You would still need to convert the arguments to the correct type, but again reflection allows you to get the required parameter count and their types.

As a bonus, the target methods can be plain old C# methods instead of requiring them to accept that struct.

C.Evenhuis
  • 25,996
  • 2
  • 58
  • 72