为什么?:运算符要求显式转换?

时间:2017-10-04 18:01:51

标签: c# if-statement casting

我有这段代码

        StateMachine.State = string.IsNullOrEmpty(MyString) ?
            (IState) StateMachine.StateA : StateMachine.StateB;

我也可以把它写成

        if (string.IsNullOrEmpty(MyString))
            StateMachine.State = StateMachine.StateA;
        else
            StateMachine.State = StateMachine.StateB;

State的类型为IStateStateAStateB均为IState

在第一个片段中,编译器需要显式强制转换,而在第二个片段中则不需要。为什么在第一个例子中需要它?

编辑: 建议的重复问题并不完全涵盖我的问题。我的问题是关于对象和接口,而另一个问题是关于原始数据类型和常数。 特别是关于声明的quetzalcoatl的建议是非常有价值的。

在建议的重复问题上阅读答案永远不会指向我。

1 个答案:

答案 0 :(得分:3)

当在表达式x ? a : b中,A和B返回不同的类型时会发生这种情况。

看看:

double a = 5;
decimal b = 4;
var z = x ? a : b;

Z的类型应该是什么?即使A和B属于某种兼容类型,比如intlong,编译器应该如何猜测返回什么?结果应该是int还是long?

在你的情况下,最有可能的是,StateA属于" classA"和StateB属于" classB"。这两个类都实现了IState,所以简单的assignement工作,但是当你把它放到?:运算符中时,编译器无法确定?:运算符的结果应该是classA还是classB

是的,我没错:编译器甚至不考虑IState。为什么?因为classA和classB可能有更多其他常见接口或基类型。他们可以 实现IState,IEnumerable或.. object极端。应该编译哪个常见的基类?这很难决定,所以它不会猜测。

有一个非常简单的解决方案,除了您自己已经发现的显式转换。只需更改StateA和StateB字段/属性的返回类型。

现在,你可能有:

class StateMachine
{
    public ClassA StateA {get .. }
    public ClassB StateB {get .. }
}

因为两者都实现IState,只需将其更改为:

class StateMachine
{
    public IState StateA {get .. }
    public IState StateB {get .. }
}

此外,后一种方式(仅通过接口提供状态实例),这可能更令人满意,因为如果StateMachine属性是一个"状态存储库"从中挑选,然后选择那些状态的代码位置可能不应该知道这些状态的确切实现类型 - 但当然这不是必需的,取决于你的设计。