2009-10-23 10 views
5

なぜ私は希望のC#多型でコンパクトにすることができないのですか?

XmlWriter writer = XmlWriter.Create(
    (string.IsNullOrEmpty(outfile) ? Console.Out : outfile) 
); 

ただし、「System.IO.TextWriter」と「string」の間に暗黙的な変換がないため、「条件式の型を判別できません」というエラーが表示されます。 ''

XmlWriter writer; 

if (string.IsNullOrEmpty(outfile)) 
{ 
    writer = XmlWriter.Create(Console.Out); // Constructor takes TextWriter 
} 
else 
{ 
    writer = XmlWriter.Create(outfile); // Constructor takes string 
} 

これら2つのCreate呼び出しは完全に有効で、これはコンパイルされます。私はインラインテストでやっているように、もっとコンパクトにする方法はありますか?

私が望むものはうまくいかないと私には分かりません。

    • 条件が真であれば、Console.Outと一緒に行き、次にそれを多相的に選択する必要があることがわかります。 TextWriterをとるXmlWriter.Create
    • 条件がfalseの場合は、outfileと一緒に移動し、文字列をとるXmlWriter.Createのバージョンを多態的に選択する必要があることがわかります。

    MLのプログラミングは私の脳を歪ませましたか?

答えて

18

コンパイラは、コンパイル時に使用するCreateのオーバーロードを選択する必要があるため、実行時に実行する必要があります。あなたはそれを作ることができ、最短はおそらくです:

XmlWriter writer = String.IsNullOrEmpty(outfile) 
    ? XmlWriter.Create(Console.Out) 
    : XmlWriter.Create(outfile); 
2

問題は、あなたが

(string.IsNullOrEmpty(outfile) ? Console.Out : outfile) 

が返すべきか、コンパイル時に決定することができないということです。それは文字列になるのか、それともTextWriterになるのでしょうか?それは実行時にのみ決定することができるため、コンパイルエラーは?演算子はコンパイル時に解決されなければなりません。

あなたはそれから抜け出すことができる最高のは、おそらく次のようになります。彼らは二つの別々のコンストラクタいるよう

XmlWriter writer = string.IsNullOrEmpty(outfile) 
    ? XmlWriter.Create(Console.Out) 
    : XmlWriter.Create(outfile); 
1

はありません、あなたは2つの別々の呼び出しを行う必要があります。

呼び出すオーバーロードはコンパイル時に決定されるため、実行時にさまざまなオーバーロードを呼び出すためにデータ型を選択することはできません。

また、条件演算子は単一のデータ型のみを返すことができ、選択肢によっては異なるデータ型を返すことはできません。

3

C#コンパイラは、コンパイル時に静的に実行するメソッドを選択します。コンパイル時に生成されるILは、特定のメソッドへの参照です。多形性部分は、実行する特定の関数の実装を選択するときに実行時に入ります。

実行時に?:文が評価されるため、コンパイラは実行するメソッドを特定できません。

これに変更しても問題ありません。

XmlWriter writer = string.IsNullOrEmpty(outfile) ? 
    XmlWriter.Create(Console.Out) : 
    XmlWriter.Create(outfile); 
1

C#は静的に型指定されていますが、多態性のマジックはすべてコンパイル時に発生しています。コンパイル時には条件式の型がわかりません。

+1

コンパイラは、コンパイル時にクラス/メソッド名と引数を選択しますが、実行時にcallvirt IL命令でそのメソッドの実装を多態的に選択します。 –

2

ここではいくつかのことが起こっています。

第1に、三元演算子(tm)のために、「例外」が発生しています。なぜなら、それを使用している場所のためではありません。問題は、単一の共通の基底型(オブジェクト以外)に解決できない2つの異なる型を返そうとする単一の式があるためです。

また、コンストラクタのオーバーロードには、まったく関係のない2つの完全に異なるタイプがあります。 C#コンパイラは非常に、非常にスマートですが、それは全くそのスマートではありません。

7

誰もが次のことを示唆しているようだ:

XmlWriter writer = String.IsNullOrEmpty(outfile) 
    ? XmlWriter.Create(Console.Out) 
    : XmlWriter.Create(outfile); 

しかし、これもなんとかです:

XmlWriter writer = XmlWriter.Create(string.IsNullOrEmpty(outfile) 
    ? Console.Out : new StreamWriter(outfile)); 

後者は、あなたのオリジナルの試みと、IMO、よりコンパクトに近いです。

関連する問題