6

私は最近 LINQ を少し使っていますが、いくつかの StackOverflowers の助けのおかげで、次のステートメントを機能させることができました。

var traceJob =
    from jobDefinition in service.JobDefinitions
    where jobDefinition.Id == traceGuid
    select jobDefinition;

if (traceJob != null && traceJob.Count() == 1)
{
 traceJob.First().RunNow();
 Console.WriteLine(traceJob.First().DisplayName + "  Last Run Time: " + traceJob.First().LastRunTime);
}

しかし、それを機能させるのはif(traceJob.Count() ==1). そのセクションを削除するObjectNullRefと、の列挙でtraceJob結果が得られなかったというエラーが表示されます。

さて、私の知る限り、ifカウントをチェックするステートメントは、実際には Linq ステートメントの結果を変更するべきではありませんよね? この動作が見られる理由を誰かに説明してもらえますか?

4

5 に答える 5

6

いいえ、そうすべきではありません。私の推測では、列挙が本当に空であり、カウント > 0 をチェックすることによってFirst()失敗しない場合に遭遇したと思います。

補足として、Any()(リポジトリの基礎となるストレージに応じて)以下よりも高速になる可能性があるため、ここで確認することをお勧めしますCount()

if (traceJob != null && traceJob.Any())
{
 traceJob.First().RunNow();
 Console.WriteLine(traceJob.First().DisplayName + "  Last Run Time: " + traceJob.First().LastRunTime);
}
于 2012-11-26T16:57:11.347 に答える
4
var traceJob =
    (from jobDefinition in service.JobDefinitions
    where jobDefinition.Id == traceGuid
    select jobDefinition).SingleOrDefault();

singleOrDefault を使用して、単一の結果を確認できます。条件に一致する結果が返されるwhereか、一致が見つからない場合は null が返されます。クエリに一致するものが複数見つかった場合、例外がスローされます。

これは、あなたtracejob == nullだけでなく、tracejob.count == 1条件をカバーしています。

MSDN の記事

于 2012-11-26T16:58:51.663 に答える
2

あなたの問題は、宣言された場所からではなく、呼び出されたときに linq ステートメントがどのように実行されるかに起因すると思います。

だからあなたの声明:

var traceJob =
    from jobDefinition in service.JobDefinitions
    where jobDefinition.Id == traceGuid
    select jobDefinition;

これは、機能的には次のものとほぼ同等です。

IEnumerable<JobDefinition> GetJobDefinitions(YourService service, Guid traceGuid) 
{
    foreach(var jobDefinition in service.JobDefinitions) 
        if(jobDefinition.Id == traceGuid) 
            yield return jobDefinition;
}

したがって、電話をかけるときは、電話をかけるのとtraceJob.Count()同じことをしていて、電話をGetJobDefinitions(service, traceGuid).Count()かけるたびtraceJob.First()に再びループにぶつかっています。

service.JobDefinitions何度も呼び出すことができる場合、これはおそらく問題ではありません。ただし、結果が時間の経過とともに変化する場合 (たとえば、実行中にジョブが追加された場合)、または後続の実行で結果が異なる場合は、問題が発生します。

いずれにしても、ループを 1 回だけ実行する方がよい場合があります。

var traceJobs =
    from jobDefinition in service.JobDefinitions
    where jobDefinition.Id == traceGuid
    select jobDefinition;

// This is where the loop above actually executes - if it's empty it will return null
var firstJob = traceJobs.FirstorDefault();

if(firstJob != null)
{
    firstJob.RunNow();
    Console.WriteLine(firstJob.DisplayName + "  Last Run Time: " + firstJob.LastRunTime);
}

または、リストまたは配列に変換してループを強制的に実行することもできます。

var traceJobsExecuted = traceJobs.ToList();
于 2012-11-26T17:09:39.093 に答える
2

あなたの「サービス」の実際の実装はわかりませんが、通常、linqクエリは実際には要求された場合にのみ結果を入力します。そのため、Count() は traceJob の状態を変更し、おそらく内部コレクションにデータを取り込みます。また、First() が内部コレクションにデータを取り込まないか、通常はそうすべきであるにも関わらず、適切に行わないように見えます。

于 2012-11-26T16:56:06.810 に答える