Using conditional (?:) operator for method selection in C# (3.0)?

后端 未结 7 1970
日久生厌
日久生厌 2020-12-01 11:49

I\'m refactoring some code.

Right now there are quite a few places with functions like this:

string error;
if (a) {
   error = f1(a, long, parameter,         


        
相关标签:
7条回答
  • 2020-12-01 12:32

    For the ? to work the compiler needs an explicit type for at least one of the operands. You can provide one here via a cast operator

    (a ? (Action<T1,T2,T3,T4>)f1 : f2)(a, long, parameter, list);
    

    Replace T* with the actual types of the delegate parameters

    0 讨论(0)
  • 2020-12-01 12:35

    You'll have to instantiate one of the methods as a specific compatible delegate type. There's just no way around it. This will, unfortunately, be a little more verbose than you're looking for:

    (a ? new Action<T1, T2, T3, T4>(f1) : f2)(a, long, parameter, list);
    

    You're going to have to make the parameters involved explicit, whether that's by using an Action (or Func) generic overload that fits or declaring your own delegate type.

    This comes down to type resolution. Given the expression:

    condition ? tVal : fVal
    

    The compiler doesn't look for common assignment-compatible ancestors for tVal and fVal (and, even if it did, the litany of different delegate types to which each might be valid could be huge); if there isn't assignment compatibility between the types of tVal and fVal in either direction, the compiler makes you be explicit as to what you want.

    For what it's worth, you should be aware that taking this approach will allocate a new delegate to either f1 or f2 every time this method is called, then that delegate will be invoked, then discarded. I bring this up only because delegate invocation is slower than ordinary early-bound (or even virtual) method invocation. It may well not be a consideration and the tradeoff might be worth it, but it's still worth knowing.

    0 讨论(0)
  • 2020-12-01 12:37

    I would think something like the following would work better:

    a ? f1(a, long, parameter, list) : f2(a, long, parameter, list);

    0 讨论(0)
  • 2020-12-01 12:44

    You can do that by declaring a delegate, as you pointed out.

    I notice that you wrote that you are doing this in quite a few places. Another alternative that might be more suitable is to use interfaces. Instantiate one of two different types depending on the value of a, then call the method on that object.

    IFoo foo = a ? new Foo1() : new Foo2();
    foo.f(a, long, parameter, list);
    

    If you have multiple methods that need to change simultaneously depending on the value of a then you can include them all in the same interface and you will only need to test a once.

    0 讨论(0)
  • 2020-12-01 12:44

    Cast the result of the ternary to an Action

    ((Action<int, int>)(a ? f1 : f2))(int1, int2);
    
    0 讨论(0)
  • 2020-12-01 12:52

    If you specify a delegate type, it will allow you to do what you're asking:

        (test ? (Action<int,int>)M1 : M2)(10, 15)
    

    With the declarations:

        void M1(int a, int b)
        {
        }
    
        void M2(int a, int b)
        {
        }
    

    Tested with .Net 4, but should apply for .Net 3.5

    0 讨论(0)
提交回复
热议问题