2016-04-08 12 views
1

私は現在、C#拡張メソッドについて学んでいます。クラスにメンバーを追加すると、それらのクラスを使用するコードの下位互換性が低下するという2つの場所を読んだことがあります。メンバーを追加すると、クラスの下位互換性がどのように低下​​しますか?

私はここで、これを読んだ:TroelsonのプロC#の本の https://blogs.msdn.microsoft.com/vbteam/2007/03/10/extension-methods-best-practices-extension-methods-part-6/

とページ418を。

これは私には意味がないのでしょうか?確かに、余分なメンバーが(拡張メソッドを使わずに、クラスに追加するだけで)追加される前にそれらのクラスのインスタンスを使用するコードは、古いメソッド、プロパティ、フィールド、およびコンストラクタをすべて呼び出すことができます彼らは変わらなかったので、前に。新しいメンバーがオブジェクトの状態を変更できる場合でも、古いコードでは呼び出されないので、コードは下位互換性があります。

私はここで何を見ませんか?

+1

ある実装から別の実装にある型のインスタンスに対して、指定されたメソッドが呼び出されたときに実行されるコードの変更が、そのコードに何らかの影響を与える可能性がありますか? – Servy

+0

コードを変更するのではなく、クラスに追加しました。明らかに、他のクラスが依存しているコードでは、それが危険な手を出すことがわかります。しかし、以下の受け入れられた回答のように、特定のパラメータ(古いコードメソッド呼び出しで使用できる)の元のメソッドよりも優先されるメソッドのオーバーロードを追加することは、思った。 –

+0

@GeorgeWooding、私の答えに2番目の例を追加しました。 – devuxer

答えて

2

ここでは、実際にクライアントコードを壊す可能性があり、新たなメソッドを追加する1つの方法があります...

void Main() 
{ 
    var oldFoo = new OldFoo(); 
    var oldResult = oldFoo.Calculate(2, 2); // 4 
    var newFoo = new NewFoo(); 
    var newResult = newFoo.Calculate(2, 2); // 0 
} 

public class OldFoo 
{ 
    public int Calculate(params int[] values) 
    { 
     return values.Sum(); 
    } 
} 

public class NewFoo 
{ 
    public int Calculate(params int[] values) 
    { 
     return values.Sum(); 
    } 

    public int Calculate(int value1, int value2) 
    { 
     return value1 - value2; 
    } 
} 

そして、ここでは

初め...、特に拡張メソッドを扱う別の方法ですクライアントは、FooCombineの能力を与える拡張方法を定義します。

void Main() 
{ 
    var foo = new Foo(); 
    var result = foo.Combine(2, 2); // "22" 
} 

public static class Extensions // added by client 
{ 
    public static string Combine(this Foo foo, params int[] values) 
    { 
     return string.Join(string.Empty, values.Select(x => x.ToString())); 
    } 
} 

public class Foo { } 

その後、Fooの開発者がクラスに新しいCombineメソッド追加:拡張メソッドが効果的にブロックされるかが新しいCombineインスタンスメソッドでを影にすることを

void Main() 
{ 
    var foo = new Foo(); 
    var result = foo.Combine(2, 2); // 4 
} 

public static class Extensions 
{ 
    public static string Combine(this Foo foo, params int[] values) 
    { 
     return string.Join(string.Empty, values.Select(x => x.ToString())); 
    } 
} 

public class Foo 
{ 
    public int Combine(params int[] values) 
    { 
     return values.Sum(); 
    } 
} 

注意を。

-1

現実世界の類推が役立つかもしれません。それは機械のように考えてください。誰かが何人かの機器、例えばハーベスターの基礎として使い始めるエンジンを設計するとします。エンジン設計者が燃料フィルタが有用であると判断し、それを追加すると、ハーベスタ設計が破損する可能性があるため、新しい燃料フィルタが現在占めているスペースに何かが配置されている可能性があります。

新しいメンバ(燃料ポンプ)を追加すると、後方互換性が低下しました。収穫機の設計は、過去のバージョンの歴史に基づいていました。

さらにプログラミングベースの例:アプリケーションデザイナーは、特定の方法で動作するアプリケーション用のパーサーを作成します。リリース後、パーサーはいくつかの稀な条件に対して仕様を正しく実装していないことが判明しました。新しいバージョンがリリースされ、仕様が正しく実装されていますが、以前の動作を提供するフラグが追加されています。

1

重要なことは、拡張メソッドがメンバーメソッドと同じ名前空間を共有している場合、メンバメソッドが名前によって単純に優先されることです。これは、図書館の開発者として、自分のアプリケーションで自分のクラスに拡張メソッドを導入したクライアントのコードを壊す可能性があることを意味します。あなたがそれをやっていることをあなたが知ることができなければ。

ライブラリクラスを新しいメンバメソッドで更新し、クライアントが更新プログラムをインストールすると、新しいメソッドが以前に追加した拡張メソッドと同じ名前を持つことがあります。あるいは、引数リストに互換性がある場合、それを見つけることができないかもしれません。彼の拡張メソッドは、あなたの新しいメンバメソッドによって隠されるようになりました。彼のコードは現在コンパイルされていません(互換性のない引数リスト)、または悪いことに、異なる動作をします。