11

条件演算子を使用しようとしていますが、結果が正しいと思われる型に行き詰まっています。

以下は、私が抱えている問題を示すために考案した例です。

class Program
{
    public static void OutputDateTime(DateTime? datetime)
    {
        Console.WriteLine(datetime);
    }

    public static bool IsDateTimeHappy(DateTime datetime)
    {
        if (DateTime.Compare(datetime, DateTime.Parse("1/1")) == 0)
            return true;

        return false;
    }

    static void Main(string[] args)
    {
        DateTime myDateTime = DateTime.Now;
        OutputDateTime(IsDateTimeHappy(myDateTime) ? null : myDateTime);
        Console.ReadLine();                        ^
    }                                              |
}                                                  |
// This line has the compile issue  ---------------+

上記の行で、次のコンパイル エラーが発生します。

'< null >' と 'System.DateTime' の間に暗黙的な変換がないため、条件式の型を特定できません

パラメーターが null 許容型 (DateTime?) であるため、混乱しています。なぜ変換する必要があるのですか?null の場合はそれを使用し、日時の場合はそれを使用します。

私は次のような印象を受けました。

condition ? first_expression : second_expression;

は次と同じでした:

if (condition)
   first_expression;
else
   second_expression;

明らかにそうではありません。この背後にある理由は何ですか?

(注:「myDateTime」をnull許容のDateTimeにするとうまくいくことはわかっています。しかし、なぜそれが必要なのですか?

先に述べたように、これは不自然な例です。私の実際の例では、「myDateTime」は、null 可能にできないデータ マップ値です。)

4

5 に答える 5

22

コンパイラは、結果の使用法から条件演算子の結果の型を推測するのではなく、その引数の型から推測します。コンパイラは、結果の型を推測できないため、この式を見ると失敗します。

IsDateTimeHappy(myDateTime) ? null : myDateTime;

nullとは互換性がないためDateTime、型がどうあるべきかをコンパイラに伝える必要があります。キャストはトリックを行う必要があります:

DateTime? x = IsDateTimeHappy(myDateTime) ? (DateTime?)null : myDateTime;
OutputDateTime(x);

これで、コンパイラに問題はなくなります。必要に応じて、上記を 1 行で記述することもできます (ただし、私はおそらくこれを行いません)。

OutputDateTime(IsDateTimeHappy(myDateTime) ? (DateTime?)null : myDateTime);

Eric Lippert には、ここでも関連する適切な回答があり、コンパイラが型を決定する方法について詳しく説明しています。

于 2010-05-11T23:06:26.250 に答える
2

その理由は、三項演算子が両方のオペランドが同じ型であると想定しているためです。演算子全体は、結果に割り当てられる (この場合は関数に渡される) 前に解決されるため、コンパイラは結果の型が何であるかを知ることができません。

IsDateTimeHappy(myDateTime) ? null : myDateTime

上記の場合、 と の間nullに変換パスはありませんDateTime。それらの 1 つを にキャストするとすぐにDateTime?、コンパイラはもう 1 つを変換できます。

IsDateTimeHappy(myDateTime) ? (DateTime?)null : myDateTime
//OR
IsDateTimeHappy(myDateTime) ? null : (DateTime?)myDateTime

上記のコードの最初の行が機能するのは、コンパイラが暗黙的な変換演算子DateTimeを介して変換できるためです。DateTime?

//In Nullable<T>
public static implicit operator T?(T value);

後者は参照型であるため、nullに割り当てることができるため、2行目は機能します。DateTime?

于 2010-05-11T23:08:17.013 に答える
1

return ステートメントでは、暗黙的な変換は許可されていません。もしあなたが持っていたら

if (condition)
    return first_expression;
else
    return second_expression;

次に、リンゴとリンゴを比較します。そして、あなたが述べたように、問題はありません。

あなたの場合、DateTime のスタック上に非常に多くのスペースが割り当てられています。これは null 非許容値型です。したがって、コンパイラにとって意味のないステートメントを作成しています。あなたが言うなら、私はあなたに anAまたは aを渡すつもりですがB、と は同じものである必要がありますABあなたの場合、 は になるBことはありませんA

于 2010-05-11T23:04:10.583 に答える
0

コンパイラが言っていることは次のとおりです。

IsDateTimeHappy(myDateTime)がの場合、 に等しいfalse型の値を返す必要があります。である場合、 に等しい値を返す必要がありますが、それがどの型であるべきか教えてくれませんでした!DateTimemyDateTimetruenull

だからこそ、マークの答えが解決策です。条件が の場合に返される値の型をコンパイラに伝えるキャストを指定すると、コンパイラはとの戻り値を同じ型に変換できる (または同じ型である)trueかどうかを確認できます。truefalse

乾杯マーク!;-)

于 2010-05-11T23:08:27.587 に答える
0

null使用する代わりにdefault(DateTime?)、三項の両側に互換性のある型があります。

于 2010-05-11T23:12:40.953 に答える