在C#(3.0)中使用条件(?:)运算符进行方法选择?

时间:2011-03-03 20:52:45

标签: c# .net .net-3.5

我正在重构一些代码。

现在有很多地方都有这样的功能:

string error;
if (a) {
   error = f1(a, long, parameter, list);
}
else {
   error = f2(the_same, long, parameter, list);
}

在重构f1和f2之前(虽然很大但做类似的事情),我想重构为:

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

正如人们在C中所做的那样。(函数签名是相同的)

但是我收到了一个错误:

“错误13无法确定条件表达式的类型,因为'方法组'和'方法组'之间没有隐式转换”

这将允许我认识到参数列表是相同的,初始重构给出了不变的行为,并且还在一个地方重构了调用,确保在这些各种重构期间所有内容都没有因为我改变调用接口而被破坏方法。

我是否遗漏了一些小的内容,这些内容允许接近此语法(与一大堆额外的委托类型定义等相反)?

很抱歉编辑,但实际上有一个返回值,是的,不幸的是,它是一个字符串。 - (

现在,我正在解决这个问题:

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

问题是参数列表确实很长,并且会被重构,我更愿意先将它们合并,然后在我更改时处理编译器错误。

7 个答案:

答案 0 :(得分:16)

要使?起作用,编译器需要至少一个操作数的显式类型。您可以通过演员

在此处提供一个
(a ? (Action<T1,T2,T3,T4>)f1 : f2)(a, long, parameter, list);

T*替换为委托参数的实际类型

答案 1 :(得分:7)

您必须将其中一个方法实例化为特定的兼容委托类型。没有办法绕过它。不幸的是,这将比你正在寻找的更加冗长:

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

您将不得不明确地使用参数,无论是使用适合或声明您自己的委托类型的Action(或Func)泛型重载。

这归结为类型分辨率。鉴于表达式:

condition ? tVal : fVal

编译器不会为tValfVal寻找与公共分配兼容的祖先(并且,即使它确实如此,每个可能有效的一系列不同委托类型可能< EM>巨大);如果在任一方向上tValfVal的类型之间没有赋值兼容性,编译器会使您明确表达您想要的内容。

对于它的价值,您应该知道,每次调用此方法时,采用此方法都会将新委托分配给f1f2,然后将调用该委托,然后将其丢弃。我提出这个问题只是因为委托调用比普通的早期绑定(甚至虚拟)方法调用慢。它可能不是一个考虑因素,权衡可能是值得的,但它仍然值得知道

答案 2 :(得分:6)

如果您指定委托类型,它将允许您执行您要求的操作:

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

声明:

    void M1(int a, int b)
    {
    }

    void M2(int a, int b)
    {
    }

使用.Net 4测试,但应该申请.Net 3.5

答案 3 :(得分:6)

您可以通过声明代理来实现,正如您所指出的那样。

我注意到你写过你在很多地方这样做。另一种可能更合适的替代方案是使用接口。根据a的值实例化两种不同类型中的一种,然后在该对象上调用该方法。

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

如果您有多个方法需要根据a的值同时更改,那么您可以将它们全部包含在同一个界面中,您只需要测试a一次。

答案 4 :(得分:1)

不,基本上,不会降低效率。如果有返回值,您可以使用:

var result = cond ? methodA(a,b,c,d) : methodB(a,b,c,d);

但就是这样。

好吧,你可以从方法组创建一对委托,但这没有任何充分的理由增加了开销。我不会支持它。

答案 5 :(得分:1)

我认为以下内容会更好:

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

答案 6 :(得分:0)

将三元组的结果投射到Action

((Action<int, int>)(a ? f1 : f2))(int1, int2);