3

null許容のDateTimeオブジェクトを使用していて、奇妙な動作に遭遇しました。サンプル関数は次のとおりです。

    public DateTime? Weird()
    {
        DateTime check = DateTime.Now;
        DateTime? dt;
        if (check == DateTime.MinValue)
            dt = null;
        else
            dt = Viewer.ActiveThroughUTC.ToLocalTime();

        //this line give a compile error
        dt = (check == DateTime.MinValue) ? (null) : (Viewer.ActiveThroughUTC.ToLocalTime());
        return dt;
    }

私の知る限り、三項演算子の行は前の4行と同じである必要がありますが、VS2010では、<null>とDateTimeの間に変換が存在しないというコンパイルエラーが発生します(問題のオブジェクトは'DateTimeですが) ?')。三項演算子について知っておくべきことはありますか、それともこれはバグですか?

4

5 に答える 5

10

?:演算子の両方の要素は同じタイプである必要があります(ただし、そうである必要はありません-以下の詳細を参照してください)。キャストnullDateTime?

dt = (check == DateTime.MinValue) ? (DateTime?)null : ...

スペックから:

?:演算子の2番目と3番目のオペランドは、条件式のタイプを制御します。XとYを2番目と3番目のオペランドのタイプとします。それで、

XとYが同じ型の場合、これは条件式の型です。

  • それ以外の場合、暗黙の変換(セクション6.1)がXからYに存在するが、YからXには存在しない場合、Yは条件式のタイプです。
  • それ以外の場合、YからXへの暗黙の変換(セクション6.1)が存在するが、XからYへの変換は存在しない場合、Xは条件式のタイプです。
  • そうしないと、式の種類を判別できず、コンパイル時エラーが発生します。

(興味深いことに、実際には「三項」演算子とは呼ばれていません。これは3値(3値)演算子の1つであり、C#では他の演算子を認識していません。「?:」演算子と呼ばれ、少し難しいです。発音します。「条件付き」演算子とも呼ばれます。)

于 2010-10-07T00:02:57.383 に答える
3

いくつかの回答は、条件演算子の両方の値が同じ型でなければならないと誤って述べています。これは明らかに真実ではなく、言語仕様のセクション7.13で詳細に説明されています。

仕様から(XとYは2つの値のタイプです)

  • XとYが同じ型の場合、これは条件式の型です。
  • それ以外の場合、暗黙の変換(§6.1)がXからYに存在するが、YからXには存在しない場合、Yは条件式のタイプです。
  • それ以外の場合、YからXへの暗黙の変換(§6.1)が存在するが、XからYへの変換は存在しない場合、Xは条件式のタイプです。
  • そうしないと、式の種類を判別できず、コンパイル時エラーが発生します。

2番目と3番目のケースでは、一方から他方への暗黙の変換がある限り、タイプを異ならせることができます(ただし、元に戻すことはできません)。

このシナリオを修正する最も簡単な方法は、オペランドの1つを明示的にDateTime?にキャストすることです。

DateTime? dt = (check == DateTime.MinValue) 
  ? (DateTime?)null
  : Viewer.ActiveThroughUTC.ToLocalTime();
于 2010-10-07T00:12:20.760 に答える
0

条件ステートメントの戻りオプションは、同じタイプ(または、最も暗黙的に変換可能なものは1つだけ)である必要があります。コンパイラーが推測するnull許容型への暗黙的な変換は次のとおりです。

dt = null;

ここでは発生しません(最初のオプションを2番目のオプションに変換する必要がある場合、またはその逆の場合)。したがって、各オプションからのリターンタイプは一致するか、変換可能である必要があります。たとえば、これは機能します。

dt = check == DateTime.MinValue ? (DateTime?)null : Viewer.ActiveThroughUTC.ToLocalTime();
于 2010-10-07T00:04:12.210 に答える
0

ternery演算子を使用する場合、引数は同じ型である必要があります。次のように変更します。

dt = (check == DateTime.MinValue) ? (DateTime?)null : 
        (DateTime?)Viewer.ActiveThroughUTC.ToLocalTime();   

DateTime2番目の引数(実際のdateime)でのキャストは、への暗黙のキャストfropmがあるため、必要ない場合がありますDateTime?。最初のキャスト(DateTime?)nullは、コンパイラにキャスト先を指示します。

于 2010-10-07T00:05:34.670 に答える
0

nullの新しいDateTime?()instreadを使用します。そうすれば、式がどのタイプであるかがわかります。

dt = check == DateTime.MinValue ? new DateTime?() : DateTime.Now;
于 2010-10-07T00:08:00.973 に答える