关于c#4.0:以接口为基类的三元表达式

Ternary Expression with Interfaces as a Base Class

我正在尝试创建三元表达式,但出现以下错误

"无法确定条件表达式的类型,因为LiveSubscription和DisconnectedSubscription之间没有隐式转换"

相同的逻辑在if语句中有效,但我想了解为什么它在三元表达式中不起作用-

这是我要执行的操作的要点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public interface IClientSubscription
{
    bool TryDisconnect();
}

public class LiveSubscription : IClientSubscription
{
    public bool TryDisconnect()
    {
        return true;
    }
}

public class DisconnectedSubscription : IClientSubscription
{
    public bool TryDisconnect()
    {
        return true;
    }
}

public class ConnectionManager
{
    public readonly IClientSubscription Subscription;

    public ConnectionManager(bool IsLive)
    {
        // This throws the exception
        Subscription = (IsLive)
            ? new LiveSubscription()
            : new DisconnectedSubscription();

        // This works
        if (IsLive)
        {
            Subscription = new LiveSubscription();
        }
        else
        {
            Subscription = new DisconnectedSubscription();
        }
    }
}

我总是可以将其切换为if / else,但我想先了解发生了什么问题!


您需要将至少一个操作数强制转换为IClientSubscription

1
2
3
Subscription = (IsLive)
            ? (IClientSubscription)new LiveSubscription()
            : new DisconnectedSubscription();

原因是三元表达式是由操作数确定的某种类型。基本上,它尝试将第二个操作数转换为第一个操作数的类型,反之亦然。两者都在这里失败,因为LiveSubscription不是DisconnectedSubscription,反之亦然。
编译器不会检查两者是否共享相同的基本类型。

尝试在评论中回答您的问题:

不,三元表达式不是某种对象,但是三元表达式是赋值的右手部分。赋值的每个右手部分表达式都具有某种类型,否则将无法将该表达式分配给左侧的变量。
例子:

  • var x = Guid.NewGuid()

    右侧表达式(Guid.NewGuid())的类型为Guid,因为方法NewGuid()返回Guid

  • var x = y.SomeMethod()

    右侧表达式的类型为SomeMethod()的返回类型。

  • var x = IsLive ?"a" : 1

    这显然是无效的,不是吗? x应该是什么类型? string还是int
    这将导致产生与您的代码完全相同的错误消息。

  • 您的示例有所更改:

    1
    2
    var subscription = (IsLive) ? new LiveSubscription()
                                : new DisconnectedSubscription();

    注意subscription之前的var,我们现在初始化一个新变量,而不是现有变量。我认为即使在这里,问题也很明显:subscription应该是什么类型? LiveSubscriptionDisconnectedSubscription?两者都不可以,因为取决于IsLive,它必须是一个。

关于与if的比较:

在您的代码中,将新的LiveSubscription实例或新的DisconnectedSubscription实例分配给subscription的情况是发生了对IClientSubscription的隐式转换,因为编译器知道subscription的类型是IClientSubscription,并且两者< x1>和DisconnectedSubscription可以隐式转换为该接口。
三元表达式的分配有些不同,因为编译器首先尝试评估三元表达式,然后才尝试将其分配给subscription。这意味着编译器不知道三元表达式的结果必须为IClientSubscription类型。