Apiを介してジョブスケジューリングサービスのjobIdを探す非同期メソッドがあります。
結果が見つからない場合は、空のタスクまたはnullを返す方がよいでしょうか。
コレクションを返すときに理解するように、nullではなく空のコレクションを返し、オブジェクトを使用する方が、空のオブジェクトよりもnullを返す方が適切です。しかし、タスクに関しては、どれが最善かわかりません。添付のメソッドを参照してください。
ありがとうございました
public virtual Task<int> GetJobRunIdAsync(int jobId)
{
var jobMonRequest = new jobmonRequest(true, true, true, true, true,
true, true, true, true, true, true, true,
true,
true, true, true, DateTime.Today, jobId, null, 0, null, null,
null, null, 0, 0);
var jobMonResponseTask = Client.jobmonAsync(jobMonRequest);
var jobTask = jobMonResponseTask.ContinueWith(task =>
{
if (jobMonResponseTask.Result == null )
{
var empty = new Task<int>(() => 0); // as i understand creating a task with a predefined result will reduce overhead.
return empty.Result; // || is it better to just return null?
}
if (jobMonResponseTask.Result.jobrun.Length > 1)
{
throw new Exception("More than one job found, Wizards are abound.");
}
return jobMonResponseTask.Result.jobrun.Single().id;
});
return jobTask;
}
結果が見つからない場合は、空のタスクまたはnullを返す方が適切ですか?
ここで考慮すべき点がいくつかあります。
まず、null Task
を返さないでください。 async
の世界では、null
タスクは意味がありません。 Task
は非同期メソッドの実行を表すので、非同期メソッドがnull
タスクを返すことは、もちろん、呼び出しコードに「実際にはこのメソッドを呼び出さなかった」ことを伝えるようなものです。した。
したがって、メソッドから返されたTask
/Task<T>
は決してnull
にはなりません。ただし、通常のタスク内でnull
valueを返すオプションはまだあります。あれは君次第だ。
タスクについては、どれが最善かわかりません。
タスクは単なるラッパーです。基本的なロジックは同じです。このメソッドが同期的である場合にどのように見えるか考えてください。戻り値の型はint
で何も見つからなかった場合は0
を返しますか、戻り値の型はint?
で何も見つからなかった場合はnull
を返しますか?同期メソッドでその選択を行った後、非同期メソッドの場合はそれをTask<T>
でラップします。
最後の注意として、私は言わなければなりません:
Task
コンストラクタを使用してください =。Task<T>.Result
を避け、代わりにawait
を使用 。ContinueWith
を使用しないでください。代わりにawait
を使用してください 。あなたの方法は劇的に単純化することができます:
public virtual async Task<int> GetJobRunIdAsync(int jobId)
{
var jobMonRequest = ...;
var jobMonResponse = await Client.jobmonAsync(jobMonRequest);
if (jobMonResponse == null)
return 0;
if (jobMonResponse.jobrun.Length > 1)
throw new Exception("More than one job found, Wizards are abound.");
return jobMonResponse.jobrun.Single().id;
}
または、null
の(タスクではなく)valueを返したい場合:
public virtual async Task<int?> GetJobRunIdAsync(int jobId)
{
var jobMonRequest = ...;
var jobMonResponse = await Client.jobmonAsync(jobMonRequest);
if (jobMonResponse == null)
return null;
if (jobMonResponse.jobrun.Length > 1)
throw new Exception("More than one job found, Wizards are abound.");
return jobMonResponse.jobrun.Single().id;
}
私の個人的な好みは、可能な限りnull
を避けることです。これにより、呼び出し側は戻り値のチェックを実装する必要があり、意図しないNullReferenceException
が削減されます。
null
を使用するのは、値型の戻り値のみです。 null可能な値型はHasValue
およびValue
プロパティを提供するため、呼び出し元は次のことができます。
var jobId = api.GetJobRunIdAsync(1234).Result; //note: highly recommend using async/await here instead of just returning a task
if(jobId.HasValue)
{
var result = DoSomethingWithId(jobId);
//continue processing...
}
int
を返すので、これはあなたが提供した例ではうまくいくと思います。
コレクションを返すときは、nullオブジェクトではなく空のコレクションを使用します。これにより分岐が少なくなり、コードの読み取りとテストが容易になります。nullコレクションが返されると、次のような結果になります。
var results = await GetResultsForJobId(1234);
if(results != null) {}
// or results?.SomeLinqOperation();
空のコレクションでは、これは単に
var results = await GetResultsForJobId(1234);
results.SomeLinqOperation();
コレクション以外のその他の参照型については、Maybe<T>
またはOptional<T>
を実装することをお勧めします。これらは、Nullable<T>
と同様の方法で参照型とともに使用できます。このような実装の例は、GitHubの https://github.com/nlkl/Optional にあります。簡単なバージョンは次のようになります:
public struct Optional<T>
{
private static readonly Optional<T> _readOnlyEmpty = new Optional<T>();
public static Optional<T> Empty => _readOnlyEmpty;
public T Value { get; }
public bool HasValue { get; private set; }
public Optional(T value)
: this()
{
Value = value;
HasValue = true;
}
public static implicit operator Optional<T>(T value)
{
return new Optional<T>(value);
}
public static implicit operator T(Optional<T> optional)
{
return optional.Value;
}
}
コレクションはnull
を実装することが多く、foreach(var item in collection)
を介して反復されるため、IEnumerable
よりも空のコレクションを返す方が適切です。
コレクションオブジェクトが空のコレクションではなくNullReferenceException
の場合、Foreachはnull
に実行されます。空のコレクションを返すと、その場合にnull参照チェックを忘れることによるプログラムのクラッシュが回避され、より直感的になります。
また、コレクションのオブジェクトは、たとえばyield
ステートメントを介して、必要なときにのみ作成できます。その前は、結果はまだ存在しないため、ここではnullが問題になる可能性があるため、ここではnullの代わりに空のコレクションを返すのが理にかなっています。
ただし、単一のオブジェクトを返す場合、そのオブジェクトが表すエンティティが存在せず、空のオブジェクト(デフォルト値に初期化されたプロパティを持つなど)と異なる可能性がある場合、nullを返すことは完全に有効です。失敗する可能性がある場合は、とにかく失敗したかどうかを確認する必要があるため、この場合のnullは問題ではなく、実際に参照が表すものがない場合の望ましい結果です。
Task
についても同様です。 Task
自体は、その完了を確認または待機するために必要です。 Task
が完了したことを確認する必要がある場合は、空のTask
を返します。 Task
完了を確認する必要がなく、それを実行して忘れるだけの場合、何かを再調整する目的は何ですか?
ここで2つのポイントがあります。最初に、有効な結果がない場合の戻り値。戻り値の型をintに変更しますか?有効な値がないことを呼び出し元に示すために、jobRun Idに対してnullを返します。
タスクを返す方法の他の部分については、ここで詳しく説明します 私のインターフェースがタスクを返す必要がある場合、操作なしの実装を行うための最良の方法は何ですか?