0

これを試すと:

Month1Value = 
    g.Where(i => DateTime.ParseExact(i.Period, fmt, cult).Month == lastMonth)
    .FirstOrDefault()
    .Value

先月のデータがあれば、Value問題なく割り当てられます。値がない場合、次の例外が発生します。

オブジェクト参照がオブジェクト インスタンスに設定されていません

ただし、上記を次のように変更すると:

Month1Value = 
     g.Where(i => DateTime.ParseExact(i.Period, fmt, cult).Month == lastMonth)
     .Select(x=>x.Value)
     .FirstOrDefault()

一致する要素がない場合は、必要に応じゼロを取得します。

これら 2 つのラムダ式の書き方の違いは何ですか?

SSCCE:

void Main() {
    var currentMonth = DateTime.Now.Month;
    var currentTimeStamp = DateTime.Now;

    int lastMonth = currentTimeStamp.AddMonths(-1).Month; // 9

    System.Globalization.CultureInfo cInfo = new System.Globalization.CultureInfo("en-US");
    System.Globalization.DateTimeFormatInfo english = cInfo.DateTimeFormat;
    var cult = System.Globalization.CultureInfo.InvariantCulture;
    string fmt = "yyyyMM";

    var DataResults = new[] {
        new Data() {Desc="Item Name", Seq=10639, Period="200906", Value=1.65M},
        new Data() {Desc="Item Name", Seq=10639, Period="200907", Value=1.56M},
        new Data() {Desc="Item Name", Seq=10639, Period="200905", Value=1.62M},
        new Data() {Desc="Item Name", Seq=10639, Period="200908", Value=1.6M}
    };

    var pivotedResults =
        DataResults
        .GroupBy(i => new { i.Desc, i.Seq })
        .Select((g, k) => new PivotedData
        {
            Desc = g.Key.Desc,
            Seq = g.Key.Seq,
            // Month1Value = g.Where(i => DateTime.ParseExact(i.Period, fmt, cult).Month == lastMonth).FirstOrDefault().Value,
            Month1Value = g.Where(i => DateTime.ParseExact(i.Period, fmt, cult).Month == lastMonth).Select(x => x.Value).FirstOrDefault(),
            Month1 = english.GetAbbreviatedMonthName(lastMonth),
        }).ToList();    

    DataResults.Dump();
    pivotedResults.Dump();
}

public class Data {
   public string Desc { get; set; }
   public long Seq { get; set; }
   public string Period { get; set; }
   public decimal Value { get; set; }
}

public class PivotedData {
   public string Desc { get; set; }
   public long Seq { get; set; }
   public string Month1 { get; set; }
   public decimal? Month1Value { get; set; }
}
4

4 に答える 4

6

答えは非常に簡単です。

最初のバージョンでは、 の後に呼び出しがあります.FirstOrDefault()。要素がない場合は、オブジェクトに対してFirstOrDefault()返されます ( msdnを参照)。nullそして.Value、null ポインターを呼び出そうとします。

2 番目のバージョンでは、これが最後の呼び出しです。その前にSelect()、列挙型が int-enumerable に変わり、デフォルトはintです0

于 2013-10-31T14:33:34.553 に答える
3

FirstOrDefaultは結果を列挙し、基準に一致する要素がない場合は 'null' を返します。これは、参照型の default(T) が null であるためです。次に、結果に対して .Value を呼び出すと、 .Value が得られますNullReferenceException

一方、Selectを使用すると、まだシーケンスを列挙していないため、クエリの残りの部分に一致する値のみを取得するため、正しい動作が得られます (つまり、 where句が考慮されます)。

于 2013-10-31T14:33:45.790 に答える
1

最初の行には、「先月から最初の i を取得し、その値を取得する」と書かれています。

問題は、先月の i がない場合、存在しないためその値を取得できないことです。

2 行目は、「先月の i の最初の値を取得するか、存在しない場合はデフォルト値 (0) を取得する」と述べています。

これにはその問題はありません。

同じ回答のより技術的なバージョンについては、他の回答を参照してください。

于 2013-10-31T14:36:36.133 に答える
1
Month1Value = 
    g.Where(i => DateTime.ParseExact(i.Period, fmt, cult).Month == lastMonth)
    .FirstOrDefault()
    .Value

nullable である ".FirstOrDefault()" の結果にアクセスしようとします。したがって、null の場合は、null ref をスローします。

Month1Value = 
     g.Where(i => DateTime.ParseExact(i.Period, fmt, cult).Month == lastMonth)
     .Select(x=>x.Value)
     .FirstOrDefault()

最初に値を選択し、次に最初の値を取得します。結果が null になる可能性はありますが、".Value" を呼び出していないため、例外はスローされません。

同じように見えるかもしれませんが、2 つの例は根本的に異なります。

于 2013-10-31T14:38:20.307 に答える