null値を許可する型はマジックナンバーよりも望ましいですか?


22

私は最近、同僚と少し議論をしています。具体的にはC#を使用していますが、これはnull許容型を持つ任意の言語に適用できます。たとえば、最大値を表す値があるとします。ただし、この最大値はオプションです。nullableな数値が望ましいと主張します。私の同僚は、先例を引用してゼロの使用を支持しています。確かに、ネットワークソケットなどでは、無制限のタイムアウトを表すためにゼロがよく使用されています。今日ソケットを処理するコードを作成する場合、タイムアウトがないという事実を表す方が良いと思うので、個人的にnull値を使用します。

どの表現が優れていますか?どちらも「なし」を意味する値の条件チェックを必要としますが、null許容型は意図を少し良く伝えると信じています。


6
数値を使用する場合は、コードに直接ではなく、定数に入れてください。
レナートディンハニ

@RenatoDinhaniConceiçãoそれは一般的なルールにすることはできません。そうしないと、すべてがソフトコーディングされてしまいます。
サイモンベルゴ

回答:


24

考慮してください:

  • 言語、

  • フレームワーク、

  • コンテキスト。

1.言語

∞を使用すると、最大のソリューションになります。

  • たとえば、JavaScriptには無限があります。C#は¹ではありません。

  • たとえば、Adaには範囲があります。C#ではできません。

C#にはint.MaxValueがありますが、あなたのケースでは使用できません。int.MaxValue最大整数である2,147,483,647です。コード内で、何かが爆発する前の最大許容圧力など、何かの最大値がある場合は、2,147,483,647を使用しても意味がありません。

2.フレームワーク

.NET Frameworkはこの点でかなり矛盾しており、マジック値の使用は批判される可能性があります。

たとえば"Hello".IndexOf("Z")、マジック値を返します-1。それは多分、それは(それをしない?)が容易になり、結果を操作します:

int position = "Hello".IndexOf("Z");
if (position > 0)
{
    DoSomething(position);
}

カスタム構造を使用するのではなく:

SearchOccurrence occurrence = "Hello".IndexOf("Z");
if (occurrence.IsFound)
{
    DoSomething(occurrence.StartOffset);
}

しかし、まったく直感的ではありません。なぜ-1ありませんか-123?初心者は、0それが「見つからない」ことを意味している、または単にタイプミスしていると誤って考えるかもしれません(position >= 0)

3.コンテキスト

コードがネットワークソケットのタイムアウトに関連している場合、一貫性を保つために何十年もの間誰もが使用していたものを使用することは悪い考えではありません。特に、0タイムアウトの場合は非常に明確です。これはゼロにできない値です。この場合にカスタムクラスを使用すると、物事を理解するのがより難しくなる場合があります。

class Timeout
{
    // A value indicating whether there is a timeout.
    public bool IsTimeoutEnabled { get; set; }

    // The duration of the timeout, in milliseconds.
    public int Duration { get; set; }
}
  • trueのDuration場合、0 に設定できIsTimeoutEnabledますか?
  • IsTimeoutEnabledfalseの場合、Duration100 に設定するとどうなりますか?

これは、複数の間違いにつながる可能性があります。次のコードを想像してください。

this.currentOperation.Timeout = new Timeout
{
    // Set the timeout to 200 ms.; we don't want this operation to be longer than that.
    Duration = 200,
};

this.currentOperation.Run();

操作は10秒間実行されます。Timeoutクラスのドキュメントを読むことなく、このコードの何が問題なのかわかりますか?

結論

  • null値がここにないという考えをうまく表現しています。提供されていません。利用不可。それは数字でも、ゼロ/空の文字列でも何でもありません。最大値または最小値には使用しないでください。

  • int.MaxValue言語自体に強く関連しています。クラスのint.MaxValue最高速度制限Vehicleや航空機の最高許容速度などには使用しないでください。

  • -1コードのような魔法の値は避けてください。それらは誤解を招きやすく、コードの間違いにつながります。

  • 最小値/最大値を指定して、より簡単な独自のクラスを作成します。たとえば、VehicleSpeedを持つことができますVehicleSpeed.MaxValue

  • 非常に特定の分野で何十年もの間一般的な慣習であり、この分野でコードを書いているほとんどの人が使用している場合、以前のガイドラインに従わずにマジック値を使用してください。

  • アプローチを混在させることを忘れないでください。例えば:

    class DnsQuery
    {
        public const int NoTimeout = 0;
    
        public int Timeout { get; set; }
    }
    
    this.query.Timeout = 0; // For people who are familiar with timeouts set to zero.
    // or
    this.query.Timeout = DnsQuery.NoTimeout; // For other people.
    

¹無限大を含む独自のタイプを作成できます。ここでは、ネイティブintタイプのみについて説明しています。


1
「一貫性を保つために何十年もの間すべての人が使用していたものを使用することは悪い考えではありません」/「ほとんどの人はこの分野でコードを書いています。」-どこかにタイプミスがありますか?
-deworde

1
@deworde MainMaは、彼自身がそのガイドラインより上で与えたガイドラインを参照していると思います。
ジョシュアドレイク

1
indexOfの例には同意しません。-1は文字列の外側にあり、Zは確かにそうです。
ジョシュアドレーク

5
「たとえば、JavaScriptには無限大があります。C#にはありません。」- ね?
BlueRaja-ダニーPflughoeft

特に「独自のクラスを作成する」ための+1は、私が提案したものです。ベアintが問題を制約するタイプについて十分に表現していないときはいつでも、より多くの情報を持つ新しい構造体(たとえば、マジック値を表す構造体のconstインスタンス、または示す列挙型)を検討してください。または、コントラクトプログラミングまたはその他のソリューションを検討してください。ただし、カスタム構造は最も簡単だと思います。
CodexArcanum

12

Nullは魔法の数よりも優れています。

重要なことは、そのような値を持たなければならない場合、魔法の効果を持つ値に名前を付け、それらの名前の定義が、魔法の値とwtfにぶつかった人に見える場所にあることを確認することです。

if (timeout == 4298435) ... // bad.
if (timeout == null) ... // bad.
if (timeout == NEVER_TIME_OUT) ... // yay! puppies and unicorns!

2
OK
マットH

2
ヌルは魔法の数より悪くありません。マジックナンバーを使用すると、マジックナンバーが何であるかがわかりません。0、-1、またはその他の値になります。nullは単なるnullです。
マルコ・fiset

9
ヌルは、価値がないことを意味します。これは、多くのマジックナンバーが表現しようとしている概念です。nullを使用可能な型でnullを使用できることは、データ型の可能な値の範囲から任意の値を1つ選択するよりもはるかに優れたソリューションです。
17

2
型に「null」がある場合、「null」を魔法の値として使用することは問題ありません。重要なことは、名前を付けることです。shootin 'として次に来る人はあなたが何を意味するのかわからないからです。Nullは、「無限」、「まだ指定されていない」、「データ構造を作成したコードのバグ」、またはその他の多くのことを意味します。次のコーダーは、名前があれば、その値が存在することを意味し、トリガーすることを意味する動作を知ることができます。
mjfgates

1
@CodeInChaos:両方ができることはわかっていますが、HasValueの方が好きです。私は実際には一般的にnullの大ファンではありませんが、HasValueを使用するnull許容型は、私にとってはOption / Maybe型に少し近いと感じています。
マットH

10

MAGIC_NUMBERコードは可能な限り絶対に避けるべきです。null意図のはるかに明確な表現です。


6

C#では、多くのCLRクラスに静的Emptyメンバーがあります。

  • System.String.Empty
  • System.EventArgs.Empty
  • System.Guid.Empty
  • System.Drawing.Rectangle.Empty
  • System.Windows.Size.Empty

これにより、空のオブジェクトを作成するためにマジック値を使用するか、nullを使用するかを覚えておく必要がなくなります。

しかし、のような単純な値型を扱っている場合はどうでしょうintか?その場合、あなたがプリミティブな強迫観念の犠牲になっているかどうかを考慮してください。明らかに単純な数値プロパティが独自のクラスまたは構造体の恩恵を受ける可能性は十分にあります。これにより、Emptyメンバーを指定し、その種類の値に固有の他の動作を追加することもできます。


3

この場合、null値は最大値がないことを示す優れた方法です。一般的に、特別なケースが問題の値が適用されないことを意味する場合、それが構成する機能を必要としないだけである場合、nullはこれを示す適切な指標です。

nullを使用して特殊なケースを表す場合の問題は、null値が1つだけであり、複数の特殊なケースが存在する可能性があることです。この場合、特別なケースを示すことができる追加のパラメーターとして列挙を渡すか、通常どおりint値を使用します。(これは基本的にNullable <>が行うことですが、enumではなくbooleanを使用し、パラメーターを単一の構造に結合します。)


3

この場合、null許容型は完全に理にかなっていると思います。

ヌルは、価値がないことを意味します。これは、値が0の数値とは明らかに異なる概念です。

「値を指定しない場合は最大値を使用してください」と言いたい場合は、nullを渡すことが正確な正しい表現方法です。


1

Null:一般的なエラー値、未指定、無効、または値の欠如。

ゼロ:(このコンテキストでは)実際の値ですが、必ずしも論理的または直感的な値ではありません。また、初期化の一般的な値。

あなたの問題のコンテキストでは、timeoutInMillisecondsプロパティはオプションであり、このアプローチのオーバーヘッドがオプションとしてそれを失格にするという言及はありません。

結論:例外があり、ソリューションは言語とドメインによって異なります。この場合、Nullを選択します。一部の人々がこれを誤解するのは、インターフェイスからデータをうまく分離できない場合です。クライアントはドキュメント(または実装)を読んで、これらの特別な値をどのように使用/処理するかを判断することを期待しているだけです。優れた抽象化レイヤーを追加することにより、使用法をより明確にすることができます。


0

ヌルはを使用するよりも悪いですMagicNumber。Nullはより適切に表現されたアイデアを表しますが、プラットフォーム間で動作が一貫しておらず、MagicNumber常に同じように機能するため、有益です。

使用される環境/言語に応じて、null

  • 単に0になる
  • 正当な値ではない可能性があります
  • 3ウェイロジックにより予期しない結果が生じる可能性があります

MagicNumber 常に同じように動作します。


0

マジックナンバーをチェックするのを忘れた場合(正しく行われます)、マジックナンバーは無意味なデータで少しの間続きます。できるだけ早く例外を発生させるnullを用意することをお勧めします。


-1

Nullは、マジックナンバーの唯一の選択肢ではありません。

public static int NO_TIMEOUT = 0;  // javaish

ヌルは悪です。上記の例では、コードが明らかにnullを処理できるため、それを回避できる可能性があります。しかし一般的に、nullを渡し始めると何が起こるかは遅かれ早かれnullポインタ例外が発生することです。最初にコードを書いたときには起こらないかもしれませんが、コードは最初のリリースよりもずっと長く維持されます。多くの場合、元の開発者ほどシステムについて詳しくない人々によって保守されています。

(たとえば)Scalaには、Optionクラスの優れた代替手段があります。Optionクラスには、Some-本当に必要な値をラップするNoneとNone-値のない2つの値のいずれかがあります。

これにより、開発者にとって、価値がない可能性があり、そのためのコードが優れていることが明らかになります。とにかく、それはそれを明らかにするはずです。

そして、すべてのマジックナンバーが問題になるわけではありません。コンテキストに応じて、1、1024などがすべて明らかになります。347?ええ、あなたはそれを避けるべきです。:-)


4
-1:「null is evil」を正当化します。
-deworde

4
番号のエイリアスを定義しても、それがまだ魔法の番号であるという事実は変わりません。
17年

まあ、おそらくあなたは私とは異なるマジックナンバーの定義を持っています。見てくださいen.wikipedia.org/wiki/...
ジョン・ストレイヤー

1
ここでジョン・ストレイヤーに同意します。Nullは、実際にADTをサポートしていない言語のADTの例です。OPはおそらくここでそれを回避することができますが、一般的には、nullを持っている言語はプログラマに少し失敗したと思います。
ジェレミーウォール
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.