2013-09-06 4 views
10

は、以下の典型的なシナリオを考えてみましょう:??でヌルオブジェクトをインスタンス化するオペレータ

if(anObject == null) 
{ 
anObject = new AClass(); 
} 

私が使用して、次の交換を考えているものを思ったんだけど?演算子:

anObject = anObject ?? new AClass(); 

2番目のフォームを使用する必要があるかどうかはわかりません。これはすばらしい省略形のようですが、最初はanObject = anObjectというコンストラクトがコード臭のように思えます。

これは妥当な行為ですか、それとも私が行方不明になっているより良い省略形ですか?あるいは、「それは3本の線です。

+2

どちらも共通しています。 –

+7

もしそれがコードの匂いであれば、最初に導入されることはありません。第2の形態はより簡潔であり、好ましいものでなければならない。 –

+0

@ JeroenVannevel: '?? '演算子がcode-smellであるかどうかは問題ではありませんが、オペランドの1つとして渡された式に戻って代入された式での使用がcode-smellです。 –

答えて

12

更新:O. R.マッパーが指摘したように

、質問は自己割り当てはコードのにおいであるかどうかで行うことです。これは私の本の6と2の3です。代入はほとんどコストのかかる操作ではなく、ほとんどの数学演算子を使用して他の領域でもそれをやります。

コード匂いではないと思う傾向があります。


私は怠け者のオブジェクトのすべての時間(あなたの例に若干のばらつき)があることを行う:

return _myClass ?? (_myClass = new MyClass()); 

が、私はそれは大丈夫だと思います。奇妙なことに、私はLazy<T>を使用する傾向がありません...理由はよくわかりませんが、やはり私は非常に頻繁に怠惰なアイテムを作ることはありません。 Lazy<T>はその意図でより表現力があり、アイテムが遅延インスタンス化されていることを読むことができますが、技術的には既存のアイテムにオーバーヘッドが追加されます(object)。私は本当にそのどちらかについて本当に心配していません。

「それを乗り越える」ことは、おそらくそのカテゴリに該当すると思います。この場合、自分自身はそれぞれ自分自身と思っています。

+1

12分後に私は答えをマークしてくれてとても感謝しています。今は感謝できません。 –

+1

私はこれらがコード臭であると主張していません。私の上記のコメントでは、 "it"が導入されたかどうかを指摘したいと思います - それは演算子自体code-smellですが、それを使用する特定の方法は質問に示されています。 –

+1

@ O.R.Mapper申し訳ありませんが、私が言いたいことは、自己割り当てに関する問題であり、それがコードの匂いかどうかということです。私の悪い。 –

6

式の結果を同じ変数に代入しないでください(例: a = b ?? new AClass(); - そのパターンは罰金であり、それは「フォールバック」の新しい既定のインスタンスのようなもののために機能します:

private MyClass anObject; 

// ... 

(anObject ?? new MyClass()).DoSomething(); 

この場合は、新しく作成されたオブジェクトは、後で再利用するために保管されていません。同じ変数に代入あなたがなまけ何かを初期化しているように、それはLazy<T>を使用して行くための、より表現方法だろう、その場合には、見え

private Lazy<MyClass> anObject = new Lazy<MyClass>(); 

// ... 

anObject.Value.DoSomething(); 

インスタンスが最新で作成されます。最後の行が実行されます。

オプションBの最適化されたILコードとオプションのA比較
+2

'Lazy 'はより表現力があり、明らかにタスク用に設計されていますが、普遍的に合意されたように「行きたい」という方法を少し読んでいます。 –

+1

@AdamHouldsworth:そうです、私は答えの言葉の選択を改善しました。 –

+1

+1です。私は通常、「ベストプラクティス」の質問から離れる傾向がありますが、私はこれがほとんどよりも無害であると感じました。あなたは "規範"に反するならば、多くの暴挙を犯す傾向があります:-P –

1
void Main() 
{ 
    AClass anObject = null; 

    // option A 
    if (anObject == null) 
    { 
     anObject = new AClass(); 
    } 
    // option B 
    anObject = anObject ? new AClass(); 
} 

:あなたは2間にはほとんど差がある見ることができるように

Option A       Option B       Description 
IL_0000: ldnull     IL_0000: ldnull     // Push a null reference on the stack. 
IL_0001: stloc.0  // anObject IL_0001: stloc.0  // anObject // Pop a value from stack into local variable 0. 
IL_0002: ldloc.0  // anObject IL_0002: ldloc.0  // anObject // Load local variable 0 onto stack 
            IL_0003: dup      // Duplicate the value on the top of the stack. 
IL_0003: brtrue.s IL_000B  IL_0004: brtrue.s IL_000C  // Branch to target if value is non-zero 
            IL_0006: pop      // Pop value from the stack 
IL_0005: newobj  AClass..ctor IL_0007: newobj  AClass..ctor // Allocate an uninitialized object or value type and call ctor 
IL_000A: stloc.0  // anObject IL_000C: stloc.0  // anObject // Pop a value from stack into local variable 0. 

を - より多くのカップルのオプションB(三項演算子を使用して)結果はスタック操作。

コンピュータが時計仕掛けの上で動作する場合を除き、あなたはたくさんのことのようにあなたの最終的なコードの違いは表示されません - あなたコードための最も読みやすい方行います。

方法1非レイジー:

+2

これは、合併する事業者がより簡潔なILを生産すると言っていますか?何も説明なしでこれだけで何が答えるかわからない、それは2回アップアップされたことは言うまでもなく... –

+1

-1これは、最適化されていないILを比較するのはとにかく無意味だからです。 – hvd

+0

採点...改善の回答... –

0

は、私は(私はほとんど使用され、このパターンを見る場合である)WPFビューモデルで使用見たパターンのいくつあり

public class ViewModel 
{ 
    private readonly SomeValue _value; 

    public ViewModel() 
    { 
     _value = new SomeValue(); 
    } 

    public SomeValue Value { get { return _value; } } 
} 

法1レイジー:

public class ViewModel 
{ 
    private readonly Lazy<SomeValue> _value = new Lazy<SomeValue>(() => new SomeValue()); 

    public SomeValue Value { get { return _value.Value; } } 
} 

方法2:

public class ViewModel 
{ 
    private SomeValue _value; 

    public SomeValue Value { get { return _value ?? (_value = new SomeValue()); } } 
} 

メソッド1とメソッド2の主な違いは、オブジェクトの作成時期と方法です。方法1 lazyはLazy(T)を使用して、作成にオーバーヘッドを追加します。大きなオブジェクトやWPFモデルでは、あまり重労働を起こさない傾向があります。大きなオブジェクトは内部で怠惰を利用して、オブジェクトの作成を妥当なものに保つことができます。

方法1レイジーと方法2は、ビューが大きい場合に非常に便利です。 UIの応答性を保つ必要があるため、オブジェクトの作成を延期するとユーザーエクスペリエンスが向上します。大きなオブジェクトが複雑なビューに関与している場合、これが必要となります。

関連する問題