3
\$\begingroup\$

I have a function that takes an object ("token") and three additional parameters of different types ("obj1", "obj2", "obj3"). The object "token" has an 'IsSatisfied' method that may take none, 1, 2, or 3 paremeters of types matching "obj1", "obj2", "obj3". Versions of "token" that have 1 or more parameters are generic. Right now, I have an inelegant solution of pattern matching the "token" against every permutation of 0, 1, 2, or 3 parameters, as shown in the code sample below.

Is there a more elegant way to write this? It works as is, but I might go to 4 parameters ("obj1", "obj2", "obj3", "obj4") in which case the list of permutations gets really long. Perhaps a solution that uses 'params' for an indefinite number of parameters. I would also be happy to drop the generic parameters on the Tokenizer class.

public class Tokenizer <T1, T2, T3>
{

    public void Test(IBoolToken token, T1 obj1, T2 obj2, T3 obj3)
    {
        if (token is IBooleanTokenable tokenable0P) tokenable0P.IsSatisfied();
        else if (token is IBooleanTokenable<T1> tokenable1P1) tokenable1P1.IsSatisfied(obj1);
        else if (token is IBooleanTokenable<T2> tokenable1P2) tokenable1P2.IsSatisfied(obj2);
        else if (token is IBooleanTokenable<T3> tokenable1P3) tokenable1P3.IsSatisfied(obj3);
        else if (token is IBooleanTokenable<T1, T2> tokenable2P1) tokenable2P1.IsSatisfied(obj1, obj2);
        else if (token is IBooleanTokenable<T1, T3> tokenable2P2) tokenable2P2.IsSatisfied(obj1, obj3);
        else if (token is IBooleanTokenable<T2, T3> tokenable2P3) tokenable2P3.IsSatisfied(obj2, obj3);
        else if (token is IBooleanTokenable<T2, T1> tokenable2P4) tokenable2P4.IsSatisfied(obj2, obj1);
        else if (token is IBooleanTokenable<T3, T1> tokenable2P5) tokenable2P5.IsSatisfied(obj3, obj1);
        else if (token is IBooleanTokenable<T3, T2> tokenable2P6) tokenable2P6.IsSatisfied(obj3, obj2);
        else if (token is IBooleanTokenable<T1, T2, T3> tokenable3P1) tokenable3P1.IsSatisfied(obj1, obj2, obj3);
        else if (token is IBooleanTokenable<T1, T3, T2> tokenable3P2) tokenable3P2.IsSatisfied(obj1, obj3, obj2);
        else if (token is IBooleanTokenable<T2, T1, T3> tokenable3P3) tokenable3P3.IsSatisfied(obj2, obj1, obj3);
        else if (token is IBooleanTokenable<T2, T3, T1> tokenable3P4) tokenable3P4.IsSatisfied(obj2, obj3, obj1);
        else if (token is IBooleanTokenable<T3, T1, T2> tokenable3P5) tokenable3P5.IsSatisfied(obj3, obj1, obj2);
        else if (token is IBooleanTokenable<T3, T2, T1> tokenable3P6) tokenable3P6.IsSatisfied(obj3, obj2, obj1);
    }

}
```
\$\endgroup\$
1
\$\begingroup\$

If this is a comment theme throughout your code I would say to make an IArgument interface that would manage your object parameters. But if this is the only time you are dealing with these obj parameters, I would say pass the arguments of IsSatisfied in as generic objects and let IsSatisfied worry about ordering the arguments by type:

    void IsSatisfied(params object[] objects)
    { 
        // T1 obj1 = <find T1 in objects>;
        // T2 obj2 = <find T2 in objects>;
        // T3 obj3 = <find T3 in objects>;
        // continue with previous implementation of IsSatisfied
    }

You would need to deal with the case when more than one of the objs is the same type.

Overall I don't like how the Test() method smells. You're passing in obj1, obj2, obj3, and possibly even obj4, every time, but you may only use obj2. What are obj1 and obj3 in this case?

\$\endgroup\$
  • \$\begingroup\$ Thanks for your comments. The sample code in my question is actually just an abstraction of my actual code to isolate the issue I am facing. You can assume that my code is not as smelly as it appears. For my purposes, keeping this logic outside of the IsSatisfied methods is better. \$\endgroup\$ – ColdPixel Oct 5 at 19:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.