web-dev-qa-db-ja.com

空のタスクまたはnullを返す方が良いですか? c#

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;
    }
8
crayoyeah

結果が見つからない場合は、空のタスクまたはnullを返す方が適切ですか?

ここで考慮すべき点がいくつかあります。

まず、null Taskを返さないでください。 asyncの世界では、nullタスクは意味がありません。 Taskは非同期メソッドの実行を表すので、非同期メソッドがnullタスクを返すことは、もちろん、呼び出しコードに「実際にはこのメソッドを呼び出さなかった」ことを伝えるようなものです。した。

したがって、メソッドから返されたTask/Task<T>は決してnullにはなりません。ただし、通常のタスク内でnullvalueを返すオプションはまだあります。あれは君次第だ。

タスクについては、どれが最善かわかりません。

タスクは単なるラッパーです。基本的なロジックは同じです。このメソッドが同期的である場合にどのように見えるか考えてください。戻り値の型はintで何も見つからなかった場合は0を返しますか、戻り値の型はint?で何も見つからなかった場合はnullを返しますか?同期メソッドでその選択を行った後、非同期メソッドの場合はそれをTask<T>でラップします。

最後の注意として、私は言わなければなりません:

あなたの方法は劇的に単純化することができます:

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;
}
9
Stephen Cleary

私の個人的な好みは、可能な限り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;
    }
}
0
E. Moffat

コレクションはnullを実装することが多く、foreach(var item in collection)を介して反復されるため、IEnumerableよりも空のコレクションを返す方が適切です。

コレクションオブジェクトが空のコレクションではなくNullReferenceExceptionの場合、Foreachはnullに実行されます。空のコレクションを返すと、その場合にnull参照チェックを忘れることによるプログラムのクラッシュが回避され、より直感的になります。

また、コレクションのオブジェクトは、たとえばyieldステートメントを介して、必要なときにのみ作成できます。その前は、結果はまだ存在しないため、ここではnullが問題になる可能性があるため、ここではnullの代わりに空のコレクションを返すのが理にかなっています。

ただし、単一のオブジェクトを返す場合、そのオブジェクトが表すエンティティが存在せず、空のオブジェクト(デフォルト値に初期化されたプロパティを持つなど)と異なる可能性がある場合、nullを返すことは完全に有効です。失敗する可能性がある場合は、とにかく失敗したかどうかを確認する必要があるため、この場合のnullは問題ではなく、実際に参照が表すものがない場合の望ましい結果です。

Taskについても同様です。 Task自体は、その完了を確認または待機するために必要です。 Taskが完了したことを確認する必要がある場合は、空のTaskを返します。 Task完了を確認する必要がなく、それを実行して忘れるだけの場合、何かを再調整する目的は何ですか?

0
Adwaenyth

ここで2つのポイントがあります。最初に、有効な結果がない場合の戻り値。戻り値の型をintに変更しますか?有効な値がないことを呼び出し元に示すために、jobRun Idに対してnullを返します。

タスクを返す方法の他の部分については、ここで詳しく説明します 私のインターフェースがタスクを返す必要がある場合、操作なしの実装を行うための最良の方法は何ですか?

0
Rahul Misra