インターフェース型の変数への代入と 3 項演算子を組み合わせるとコンパイルエラーになる

クラス A と、クラス B が IDisposable を実装しているとします。 そのときに、3 項演算子を用いて、以下のように書くことはできないようです。

class A : IDisposable { ... }
class B : IDisposable { ... }

// コンパイルエラーになる: There is no implicit conversion between 'A' and 'B'
IDisposable c = true ? new A() : new B();

IDisposable でキャストすれば問題なくコンパイルできます。

// OK
IDisposable c = true ? (IDisposable)new A() : (IDisposable)new B();

あるいは、いったん IDisposable 型の変数に格納しておいてから、3 項演算子を使う方法もあります。

IDisposable a = new A();
IDisposable b = new B();
var c = true ? a : b; // OK

背景

あるオブジェクトの配列があり、それをいくつかの異なる方法でソートする必要がでてきました。 そのため、それぞれの比較方法に応じた IComparer を実装するクラスを用意して、 それを Sort メソッドに渡してソート方法を切り替えようと考えました。

Sortメソッドに IComparer を渡すときに 3 項演算子を使おうとしたのですが、 コンパイルエラーになりましたので、かわりに IComparer を返すメソッドを作成するようにしました。

おおよそ以下のようなコードを書きました。

using System;
using System.Collections.Generic;

class Foo {}

// Foo をある方法 A で比較
class ComparerA : IComparer<Foo>
{
    public int Compare(Foo x, Foo y)
    {
        throw new NotImplementedException();
    }
}

// Foo をある方法 B で比較
class ComparerB : IComparer<Foo> 
{
    public int Compare(Foo x, Foo y)
    {
        throw new NotImplementedException();
    }
}

class Program
{
    static void Main()
    {
        var foos = new[] { new Foo() };
        
        Array.Sort(foos, new ComparerA()); // 方法 A でソート
        Array.Sort(foos, new ComparerB()); // 方法 B でソート
        
        // フラグでソート方法を切り替える。
        // 本当はこう書きたかったがコンパイルエラー:
        // There is no implicit conversion between 'ComparerA' and 'ComparerB'        
        // Array.Sort(foos, true ? new ComparerA() : new ComparerB());
        
        // 3 項演算子が使えないので、IComarer を返すメソッドを用意した
        Array.Sort(foos, CreateComparer(true));
    }

    static IComparer<Foo> CreateComparer(bool flag)
    {
        if (flag) return new ComparerA();
        return new ComparerB();
    }
}