C#でのコンストラクターの結果の確認


8

これと同様の方法で、nullのコンストラクターの結果をチェックする癖がある同僚とコードベースの作業をしています。

Person p = new Person();
if (p != null)
{
    p.Name = "John Smith";
}

.NETランドスケープについての私の理解は、例外がスローされない限り、コンストラクターは割り当てを満たされないままにしないということです。したがって、上記の場合、nullチェックは役に立ちません。いずれかpが割り当てられる、または例外は、プロパティセッターをスキップさせるスローされます。

ついでにこれについて同僚に尋ねたところ、「念のため」という言葉に沿って受動的な答えを得ました。私はこの種の「パロニアプログラミング」が好きではありません。読みやすさが損なわれ、不必要に循環的複雑度が増すと思います。このため、この行為の中止を正式に要請したいと思います。これは合理的な要求ですか?何か不足していますか?



1
少なくともコンパイラの警告か、コード分析の警告のようです。
フランクHileman

@FrankHileman-良い点... C#コンパイラには到達不能コードに関する警告(0161)がありますが、この特定のケースを検出できるかどうかは100%確実ではありません。
ジュール、

チェックを行うのは本当に標準的な方法ですか、それとも以前のバージョンからそのまま残っていますか?おそらくp = Repository.Get(123)または何かがあった
Ewan

回答:


12

私はあなたの戦いを選ぶことについて@MartinMaatに同意します。

これらの多くのルールで言語が修正されているにもかかわらず、言語が実際に理解されていないため、「念のため」の多くの場合があります。優先順位のルールが理解されていないために必要としない式を括弧でくくって言語。しかし、それでも、そのような習慣はほとんど無害です。

私は若い頃、言語の詳細を学び、そのような余分なコードを書かないようにすべきだと感じました。(私の不機嫌なことの1つにはreturn (0);不要な括弧がありました。)しかし、特にクライアントからサーバーにジャンプするなど、非常に多くの異なる言語を使用しているので、今はその立場をモデレートしています...そのような問題のたるみ。

あなたは、サイクロマティックが論理的に推論された議論に取り掛かり始めることについてポイントです。コードカバレッジ、特により高いレベルのカバレッジを見てみましょう:

  1. それぞれの決定はすべての可能な結果を​​とります

新しい操作で強制的にNULLを返すことはできないため、この条件付き操作でコードカバレッジのレベルを上げる方法ありません。  もちろん、これは組織にとって重要な場合とそうでない場合があります。

ただし、このコードカバレッジの問題のため、括弧の過剰よりも優先します。

一方、コード生成、JIT、およびオプティマイザはすべて、newed値がnullになることはないことを理解しているため、基になる生成コードはおそらく1ビットも影響を受けません。したがって、実際のコストは、可読性とソースコードカバレッジ機能の点でのみ発生します。

そのようなifステートメントの「else-part」はどのように見えるのですか?

他の部分がない場合、ルーチンの終わりから落ちるか、または他のコードに落ちる(つまりelse、これにifは当てはまらない)は潜在的に危険であると私は主張するでしょう。または、その行の下のコードでNULLも処理します。

それが読んだ場合:

p = new Object ();
if ( p != null ) {
    p.field = value;
}
else {
    throw new NullReferenceException ();
}

そして、言語が私たちのためにそれをすべて行うので、これは本当にやり過ぎです。

条件の意味を逆にすることをお勧めします—おそらくあなたの同僚はこれでより快適になるでしょう:

p = new Object ();
if ( p == null ) {
    throw new NullReferenceException ();
}
else {
    p.field = value;
}

これで、elseラッパーの削除を主張できるようになりました。これは、明らかに不要であるためです。

p = new Object ();
if ( p == null ) {
    throw new NullReferenceException ();
}
p.field = value;

これにより、「念のため」が条件付きになりましたが、後続のコードは条件付きではありません。このアプローチは、割り当てが失敗したときに、このメソッドや呼び出しチェーンでコードを実行し続けるのではなく、適切な応答がスローされることをさらに強化します(割り当て失敗の他の適切な処理なしで)。

したがって、要約すると、この慣行に対してここで論理的に推論される2つの議論があります。

  1. メモリ不足(またはコンストラクターの失敗)がnullを返すことを強制できないため、より高いコードカバレッジレベルに到達できません。
  2. 念のため」(質問で上記に示されているように)は不完全であり、そのため、nullがを超えて/過去の他のコードによってどのように処理されるかについての期待に一貫性がないため、欠陥がありますp.field = value;

基本的に、おそらくあなたの同僚は例外の使用について垣間見えているように思われます—そのようなことをここではC#で行うことはできませんが。(十分にテストされたコードが必要な場合は、nullを処理するための例外モデルと、nullの戻り値を並べて使用する非例外モデルの両方をコード化することはできません。)彼らはいくつかの光を見るでしょう!


あなたは私の同僚が例外についてフェンスの上にいることに関して頭に釘を打ちました。あなたの質問に、else私の例では条件はありません。彼らが行うことは、値がnullの場合は単に作業を省くことです。また、割り当てられたインスタンスが返された場合、そのnullチェックは伝達されます。エラーコードみたいなにおいがしますね。このケースはその問題に関連しているとは思いませんでしたが、それらは非常に関連していることを正しく指摘しました。包括的な対応ありがとうございます。コードカバレッジの問題は、私にとっては重要なことです。
ジェイソンタイラー

正しいことは、例外エラーコードを同じ場所でコーディングすることはできず、両方ともテスト可能にすることです!本当にエラーコードが必要な場合は、new操作をtry / catchでラップし、メモリ不足の例外でnullまたはエラーコード、あるいはその両方を配信して、OOMに対するC#の例外をエラーコードスタイルに効果的に変換できます。
Erik Eidt、2018

1
例外スローコードをさらに短縮しp = new Object() ?? throw new NullReferenceException();て、最適化の候補をさらに明確にすることができるでしょうか。
ウォンドラ2018

1
死んだコードが非常に大きな責任と見なされる特定のドメインがあり、FWIWは厳しく禁止されています。
RubberDuck 2018

8

おそらく、問題を回避して、より簡単な新しいc#構文があることを彼に知らせることができます(そして、nullチェックが実行されます!)

の代わりに

Person p = new Person();
if (p != null)
{
    p.Name = "John Smith";
}

書く

var p = new Person
{
    Name = "John Smith"
};

2
これでサンプルコードは解決されますが、すべての類似のケースに自動的に適用できるわけではありません。ifブロックの本体をに置き換えると、var foo = p.DoSomething()答えが適用されなくなることがわかります。
2018

これは良い提案であり、私が扱っているいくつかのケースを整理するのに役立ちます。残念ながら、私の例は多くの異なるフレーバーを持つ問題の単純化されたケースだったので、これは問題を全体として排除しません。傷つけることはできませんでした!
ジェイソンタイラー

1
@Flater次に、問題のプラノイドの人物は次のようになります。var foo = p?.DoSomething();
Eternal21

4

それは合理的な要求ですが、これはすでにあなたと彼の間の闘争になっているようです。あなたはすでに彼にそれを指摘しているかもしれません、彼はそれを変更するのをためらっていて、今あなたは問題をエスカレートすることを計画しています。その後、「勝つ」ことができます。

Robert Harveyが投稿したリンクを送信し、「興味深いと思われるC#オブジェクトの構築に関するリンクを送信しました」と言ってそのままにしておく方がスムーズな場合があります。それは彼が何をするのか正確には有害ではなく(ただ無意味)、後でopをきれいにするのは簡単です。私は言っている:あなたの戦いを選択してください。私は何度もこの状況に直面しており、振り返ってみると、多くの場合、苦労する価値がありませんでした。あなた方は、事実上何もせずに簡単にお互いを憎むようになります。はい、あなたは正しいですが、それはあなたと彼だけですが、あなたはいくつかの共通点を維持したいかもしれません。


洞察をありがとう。あなたのポイントはよく取られています。私は、戦いは賢明に選ばれなければならないことに同意します。私は「こんにちは、このメールをチェックしてください」ということを試しましたが、通常は無視されます。このタイプの「念のための」コードがコードベースでより広く浸透しているので、私はそれについて執拗にしています。それはすべてをより非決定的にするので、作業するのが難しくなります。特定のコーディングパターンに焦点を当てるのではなく、その全体的なポイントを伝えて伝えるべきでしょうか?
ジェイソンタイラー

1

あなたの技術的な質問はすでに回答されている(nullチェックは無意味です)ので、私はあなたの質問の別の側面に焦点を当てたいと思います-そのような状況に一般的に対処する方法:いくつかの基本的な事実を知らない同僚すべてのツールについて、したがって、ツールを最適ではない方法で使用します。

場合によっては、それほど影響がないこともあります。彼らが彼らの仕事を成し遂げ、あなたの仕事に干渉しないなら、あなたは問題を無視することができます。

その他の場合(例えばあなた)では、彼らはない、少なくともある程度は、あなたの仕事を妨害します。それについて何をしますか?

多くの詳細に依存すると思います。たとえば、あなたとあなたの同僚が会社にいてどれくらいの期間、会社は一般的にそのような問題にどのように対処しますか、問題はどのくらい影響しますか/あなたをいらいらさせますか、あなたは同僚とうまくやっていくことがどれほど重要か同僚とあなたとの関係、問題を引き起こしたりエスカレートしたりすることがこの関係にどの程度影響するかなど

私の個人的な見解は次のとおりです。エンジニアはツールを、ソフトウェアエンジニアはプログラミング言語を知っているべきだと思います。もちろん、誰もすべての詳細を知っているわけでnullはありませんが、コンストラクターが決して戻らないということは非常に基本的な考えです-誰もがそれを知っている必要があります。このような無意味なnullチェックを含むコードで作業する必要がある場合は、単にそれらを削除します。同僚がなぜそれらを削除したのかと尋ねられたら、なぜ彼らが無意味なのかを説明します。(必要に応じて、完全に不要なコードを削除する必要がある理由も説明します。)長い目で見れば、これはこれらの無意味なnullチェックのないコードにつながるでしょう。

これはやや傲慢に聞こえるかもしれません、そしてそれは誰にとっても正しいアプローチではないかもしれません。私は辛抱強く物事を説明するのが得意だと言われてきました。たぶんそれが私がこのアプローチをすぐに回避する傾向がある理由です。:-)

あなたは「この慣行をやめるという正式な要求」に言及しています。私はそのような詳細な正式なルールを持つ会社で働いたことはありませんが、とにかくいくつかの考えがあります。繰り返しますが、あなたの最善の行動は詳細に依存すると思います。このようなリクエストを提出すると、同僚やマネージャーの目には同僚の見栄えが悪くなる場合は、おそらくそれを行いません。一方、そのようなリクエストが一般的に歓迎すべき改善であり、他の人がこのルールを以前に守っていなかったために同僚を非難しない場合は、先に進んでください。誰も害を受けることはなく、誰もが元気になるでしょう。


しかし、問題に対処するための良い方法が見つからなかった場合は、皮肉に頼り、次のようなコードをどこにでも追加できます。

int c = a + b;
if (c == a + b)
{
    // next steps
}
else 
{
    throw new ArithmeticException();
}

コンストラクタ呼び出し後のnullチェックと同じくらい無意味ですが、さらに明白です。そしてもちろん、私は実際にはこれをしません。同僚にうんざりしていてとにかくやめるつもりでない限り。;-)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.