[解決済み】.NETのAPIブレークスルーのための決定版ガイド
質問
.NET/CLRのAPIバージョン管理について、特にAPIの変更がクライアントアプリケーションをどのように破壊するか、しないかについて、できるだけ多くの情報を集めたいと考えています。まず、いくつかの用語を定義しましょう。
API変更 - パブリックメンバを含む、ある型の公に見える定義における変更。これには、型名やメンバー名の変更、型の基本型の変更、型の実装インターフェース一覧からのインターフェースの追加/削除、メンバー(オーバーロードを含む)の追加/削除、メンバーの可視性の変更、メソッドや型パラメータの名前の変更、メソッドパラメータのデフォルト値の追加、型やメンバーに対する属性の追加/削除、型やメンバーに対する汎用型パラメータの追加/削除(何か見逃しましたか)が含まれます。これには、メンバー本体の変更や、プライベートメンバーの変更は含まれません(つまり、Reflectionは考慮していません)。
バイナリレベルのブレーク - API の変更により、古いバージョンの API に対してコンパイルされたクライアントアセンブリが、新しいバージョンでロードされない可能性があること。例:メソッドのシグネチャを変更し、以前と同じ方法で呼び出せるようにした場合(例:voidから戻り値の型/パラメータのデフォルト値をオーバーロードする)。
ソースレベルのブレーク - API の変更により、古いバージョンの API に対してコンパイルするように書かれた既存のコードが、新しいバージョンでコンパイルできない可能性があります。ただし、既にコンパイル済みのクライアントアセンブリは従来通り動作します。例:新しいオーバーロードを追加した場合、以前は明確だったメソッド呼び出しが曖昧になる可能性があります。
ソースレベルのクワイエットセマンティクス変更 - API の変更により、古いバージョンの API に対してコンパイルするために書かれた既存のコードが、例えば異なるメソッドを呼び出すことによって、静かにそのセマンティクスを変更することです。しかし、そのコードは警告やエラーなしにコンパイルを続け、以前にコンパイルされたアセンブリは以前と同様に動作するはずです。例: 既存のクラスに新しいインターフェイスを実装すると、オーバーロードの解決時に異なるオーバーロードが選択されるようになります。
最終的な目標は、できるだけ多くのブレーキングとクワイエットセマンティックスのAPI変更をカタログ化し、ブレーキングの正確な効果と、どの言語がその影響を受けるか受けないかを記述することである。後者について説明すると、ある種の変更はすべての言語に普遍的に影響するが(例えば、インターフェースに新しいメンバーを追加すると、どの言語でもそのインターフェースの実装が壊れる)、あるものは壊れるために非常に特定の言語のセマンティクスが入り込むことを必要とする。これは最も典型的な例で、メソッドのオーバーローディングや、一般的には暗黙の型変換に関係するものです。CLS準拠の言語(CLI仕様で定義されたquot;CLS consumerのルールに少なくとも適合している言語)であっても、quot;最小公倍数(least common denominator)を定義する方法はないようです(ここが間違っていると訂正されたらありがたいですが)ので、これは言語ごとに行うしかないでしょう。最も興味があるのは、当然ながら、.NETに最初から付属しているものです。しかし、IronPython、IronRuby、Delphi Prismなど他の言語も関連性があります。また、メソッドのオーバーロード、オプション/デフォルト・パラメータ、ラムダ型推論、変換演算子などの微妙な相互作用は、時に非常に驚くべきものになります。
まず、いくつかの例を挙げてみましょう。
新しいメソッドのオーバーロードを追加する
種類:ソースレベルブレーク
影響を受ける言語 C#, VB, F#
変更前のAPI
public class Foo
{
public void Bar(IEnumerable x);
}
変更後のAPIです。
public class Foo
{
public void Bar(IEnumerable x);
public void Bar(ICloneable x);
}
変更前に動作し、変更後に壊れたクライアントコードのサンプル。
new Foo().Bar(new int[0]);
暗黙の変換演算子オーバーロードの新規追加
種類:ソースレベルのブレーク。
対象言語 C#、VB
影響を受けない言語 F#
変更前のAPI
public class Foo
{
public static implicit operator int ();
}
変更後のAPIです。
public class Foo
{
public static implicit operator int ();
public static implicit operator float ();
}
変更前に動作し、変更後に壊れたクライアントコードのサンプル。
void Bar(int x);
void Bar(float x);
Bar(new Foo());
注意事項 F# はオーバーロードされた演算子を明示的にも暗黙的にも言語レベルでサポートしていないため、壊れることはありません。
op_Explicit
と
op_Implicit
メソッドを使用します。
新しいインスタンスメソッドの追加
種類:ソースレベルの静かなセマンティクスの変更。
影響を受ける言語 C#、VB
影響を受けない言語 F#
変更前のAPI
public class Foo
{
}
変更後のAPIです。
public class Foo
{
public void Bar();
}
静かなセマンティクスの変更を受けるクライアントコードのサンプル。
public static class FooExtensions
{
public void Bar(this Foo foo);
}
new Foo().Bar();
注意事項 F# は、言語レベルでのサポートがないため、壊れていません。
ExtensionMethodAttribute
また、CLS 拡張メソッドは静的メソッドとして呼び出される必要があります。
どのように解決するのですか?
メソッドのシグネチャを変更する
種類 バイナリレベルのブレーク
影響を受ける言語 C# (VBとF#の可能性が高いが未検証)
変更前のAPI
public static class Foo
{
public static void bar(int i);
}
変更後のAPI
public static class Foo
{
public static bool bar(int i);
}
変更前に動作していたクライアントコードのサンプル
Foo.bar(13);
関連
-
[解決済み] 権限 '*' を持つ SSL/TLS の安全なチャネルを確立できませんでした。
-
[解決済み] .NETでのdecimal, float, doubleの違い?
-
[解決済み] なぜList<T>を継承しないのですか?
-
[解決済み] .NETでC#オブジェクトをJSON文字列に変換するには?
-
[解決済み] .NETでフォーマット文字列のブレース(中括弧)をエスケープする方法
-
[解決済み] .NETコンソールアプリケーションでアプリケーションのパスを取得するにはどうすればよいですか?
-
[解決済み] .NET Coreと.NET Standard Class Libraryのプロジェクトタイプの違いは何ですか?
-
[解決済み] .NET String.Format()で数値の千の位にカンマを追加する
-
[解決済み] .NETでGmailを使ったメール送信
-
[解決済み] .NETでapp.configやweb.configから設定を読み込む
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] app.configのマッピングがないアセンブリのapp.configの再マッピングを考慮する。
-
[解決済み] ポストバックまたはコールバックの引数が無効です。 イベント検証は '<pages enableEventValidation="true"/>' を使用して有効になっています。
-
[解決済み] Visual Studioの "ターゲットフレームワーク "が見つからない
-
[解決済み] ファイルまたはアセンブリ 'System.Data.SQLite' をロードできませんでした。
-
[解決済み] Powershell v3 Invoke-WebRequest HTTPSエラー
-
[解決済み] app.configが作成されるタイミングとapp.exe.configが作成されるタイミング、その違いとは?
-
[解決済み] RelativeSourceでWPFバインディングを使用するにはどうしたらいいですか?
-
[解決済み] プライベートメソッドのユニットテストはどのように行うのですか?
-
[解決済み] WCF - メッセージサイズのクォータを増加させる方法
-
[解決済み】TypeLoadExceptionが「実装がない」というが、実装はされている