238

.NET / CLRでのAPIのバージョン管理、特にAPIの変更がクライアントアプリケーションをどのように破壊するか、または破壊しないかについて、できるだけ多くの情報を収集したいと思います。まず、いくつかの用語を定義しましょう。

APIの変更-パブリックメンバーのいずれかを含む、タイプのパブリックに表示される定義の変更。これには、タイプとメンバーの名前の変更、タイプの基本タイプの変更、タイプの実装されたインターフェイスのリストからのインターフェイスの追加/削除、メンバーの追加/削除(オーバーロードを含む)、メンバーの可視性の変更、メソッドとタイプのパラメーターの名前変更、デフォルト値の追加が含まれますメソッドパラメーター、型とメンバーの属性の追加/削除、および型とメンバーの汎用型パラメーターの追加/削除(何か見落としましたか?)。これには、メンバー本体の変更やプライベートメンバーの変更は含まれません(つまり、リフレクションは考慮されません)。

バイナリレベルの中断-APIの変更により、古いバージョンのAPIに対してコンパイルされたクライアントアセンブリが新しいバージョンで読み込まれない可能性があります。例:以前と同じ方法で呼び出すことができる場合でも、メソッドのシグネチャを変更します(つまり、voidでタイプ/パラメーターのデフォルト値のオーバーロードを返します)。

ソースレベルの中断-APIの変更により、古いバージョンのAPIに対してコンパイルするように記述された既存のコードが、新しいバージョンでコンパイルされない可能性があります。ただし、コンパイル済みのクライアントアセンブリは以前と同じように機能します。例:以前は明確であったメソッド呼び出しにあいまいさをもたらす可能性のある新しいオーバーロードを追加します。

ソースレベルの静かなセマンティクスの変更-古いバージョンのAPIに対してコンパイルするように記述された既存のコードが、別のメソッドを呼び出すなどして、そのセマンティクスを静かに変更するAPIの変更。ただし、コードは警告/エラーなしでコンパイルを継続する必要があり、以前にコンパイルされたアセンブリは以前と同じように機能するはずです。例:既存のクラスに新しいインターフェースを実装すると、過負荷の解決中に別の過負荷が選択されます。

最終的な目標は、可能な限り多くの破壊的で静かなセマンティクスAPIの変更をカタログ化し、破壊の正確な影響と、それによって影響を受ける言語と影響を受けない言語を説明することです。後者を拡張するには:一部の変更はすべての言語に普遍的に影響しますが(たとえば、インターフェイスに新しいメンバーを追加すると、任意の言語でのそのインターフェイスの実装が機能しなくなります)、一部の変更では、中断するために非常に特殊な言語セマンティクスが必要になります。これには通常、メソッドのオーバーロードが含まれ、一般に、暗黙的な型変換に関係するものはすべて含まれます。ここでは、CLS準拠の言語(つまり、CLI仕様で定義されている「CLSコンシューマー」のルールに少なくとも準拠している言語)についても、「最小公分母」を定義する方法はないようです。誰かが私をここで間違っていると訂正してくれれば幸いです-ですから、これは言語ごとに行わなければなりません。最も興味深いのは、当然、.NETに付属しているC#、VB、F#です。ただし、IronPython、IronRuby、DelphiPrismなどの他のものも関連しています。コーナーケースが多いほど、興味深いものになります。メンバーの削除などはかなり自明ですが、メソッドのオーバーロード、オプション/デフォルトパラメーター、ラムダ型推論、変換演算子などの間の微妙な相互作用は非常に驚くべきものです。時には。

これをキックスタートするためのいくつかの例:

新しいメソッドのオーバーロードを追加する

種類:ソースレベルのブレーク

影響を受ける言語: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_Explicitop_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();

ExtensionMethodAttribute注:F#は、の言語レベルのサポートがなく、静的メソッドとしてCLS拡張メソッドを呼び出す必要があるため、壊れていません。

4

17 に答える 17

46

メソッドシグネチャの変更

種類:バイナリレベルのブレーク

影響を受ける言語: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);
于 2009-09-24T17:00:45.447 に答える
43

デフォルト値でパラメータを追加します。

休憩の種類:バイナリレベルの休憩

呼び出し元のソースコードを変更する必要がない場合でも、(通常のパラメーターを追加する場合と同様に)再コンパイルする必要があります。

これは、C#がパラメーターのデフォルト値を呼び出し元のアセンブリに直接コンパイルするためです。これは、再コンパイルしないと、古いアセンブリがより少ない引数でメソッドを呼び出そうとするため、MissingMethodExceptionが発生することを意味します。

変更前のAPI

public void Foo(int a) { }

変更後のAPI

public void Foo(int a, string b = null) { }

後で壊れたサンプルクライアントコード

Foo(5);

Foo(5, null)クライアントコードは、バイトコードレベルで再コンパイルする必要があります。呼び出されたアセンブリには、のみが含まれFoo(int, string)、は含まれませんFoo(int)。これは、デフォルトのパラメーター値が純粋に言語機能であるため、.Netランタイムはそれらについて何も認識していません。(これは、デフォルト値がC#のコンパイル時定数でなければならない理由も説明しています)。

于 2014-05-07T12:13:02.730 に答える
26

これは、特にインターフェースの同じ状況との違いを考えると、私がそれを発見したときは非常に明白ではありませんでした。それはまったく休憩ではありませんが、私がそれを含めることにしたのは驚くべきことです:

クラスメンバーを基本クラスにリファクタリングする

種類:休憩ではありません!

影響を受ける言語:なし(つまり、壊れているものはありません)

変更前のAPI:

class Foo
{
    public virtual void Bar() {}
    public virtual void Baz() {}
}

変更後のAPI:

class FooBase
{
    public virtual void Bar() {}
}

class Foo : FooBase
{
    public virtual void Baz() {}
}

変更中ずっと機能し続けるサンプルコード(私はそれが壊れると思っていたとしても):

// C++/CLI
ref class Derived : Foo
{
   public virtual void Baz() {{

   // Explicit override    
   public virtual void BarOverride() = Foo::Bar {}
};

ノート:

C ++ / CLIは、仮想基本クラスメンバーの明示的なインターフェイス実装に類似した構造(「明示的なオーバーライド」)を持つ唯一の.NET言語です。インターフェイスメンバーをベースインターフェイスに移動する場合と同じ種類の破損が発生することを完全に予想していました(明示的なオーバーライド用に生成されたILは、明示的な実装の場合と同じであるため)。驚いたことに、これは当てはまりません-生成されたILは、オーバーライドではなくBarOverrideオーバーライドを指定していますが、アセンブリローダーは、文句なしに正しく置換できるほど賢いです-明らかに、クラスであるという事実が違いを生みます。図に行く...Foo::BarFooBase::BarFoo

于 2009-10-05T22:24:58.403 に答える
21

これはおそらく「インターフェイスメンバーの追加/削除」というそれほど明白ではない特殊なケースであり、次に投稿する別のケースに照らして、独自のエントリに値すると思いました。それで:

インターフェイスメンバーをベースインターフェイスにリファクタリングする

種類:ソースレベルとバイナリレベルの両方でブレーク

影響を受ける言語:C#、VB、C ++ / CLI、F#(ソースブレーク用、バイナリ1は自然にすべての言語に影響します)

変更前のAPI:

interface IFoo
{
    void Bar();
    void Baz();
}

変更後のAPI:

interface IFooBase 
{
    void Bar();
}

interface IFoo : IFooBase
{
    void Baz();
}

ソースレベルでの変更によって壊れたサンプルクライアントコード:

class Foo : IFoo
{
   void IFoo.Bar() { ... }
   void IFoo.Baz() { ... }
}

バイナリレベルでの変更によって壊れたサンプルクライアントコード。

(new Foo()).Bar();

ノート:

ソースレベルのブレークの場合、問題は、C#、VB、およびC ++ / CLIがすべて、インターフェイスメンバーの実装の宣言で正確なインターフェイス名を必要とすることです。したがって、メンバーがベースインターフェイスに移動すると、コードはコンパイルされなくなります。

バイナリブレークは、インターフェイスメソッドが明示的な実装用に生成されたILで完全に修飾されているためであり、インターフェイス名も正確である必要があります。

利用可能な場合の暗黙的な実装(つまり、C#とC ++ / CLI、ただしVBではない)は、ソースレベルとバイナリレベルの両方で正常に機能します。メソッド呼び出しも壊れません。

于 2009-10-05T22:18:20.773 に答える
16

列挙値の並べ替え

休憩の種類:ソースレベル/バイナリレベルの静かなセマンティクスの変更

影響を受ける言語:すべて

リテラルは同じ名前であるため、列挙値を並べ替えるとソースレベルの互換性が維持されますが、序数のインデックスが更新されるため、ある種のサイレントソースレベルの中断が発生する可能性があります。

さらに悪いことに、クライアントコードが新しいAPIバージョンに対して再コンパイルされない場合に発生する可能性のあるサイレントバイナリレベルのブレークがあります。列挙値はコンパイル時定数であるため、それらの使用はすべてクライアントアセンブリのILに組み込まれます。このケースは、特に見つけるのが難しい場合があります。

変更前のAPI

public enum Foo
{
   Bar,
   Baz
}

変更後のAPI

public enum Foo
{
   Baz,
   Bar
}

動作するが後で壊れたサンプルクライアントコード:

Foo.Bar < Foo.Baz
于 2014-01-04T20:47:52.540 に答える
13

これは実際には非常にまれなことですが、それでもそれが起こったときは驚くべきことです。

オーバーロードされていない新しいメンバーの追加

種類:ソースレベルの中断または静かなセマンティクスの変更。

影響を受ける言語:C#、VB

影響を受けない言語:F#、C ++ / CLI

変更前のAPI:

public class Foo
{
}

変更後のAPI:

public class Foo
{
    public void Frob() {}
}

変更によって壊れたサンプルクライアントコード:

class Bar
{
    public void Frob() {}
}

class Program
{
    static void Qux(Action<Foo> a)
    {
    }

    static void Qux(Action<Bar> a)
    {
    }

    static void Main()
    {
        Qux(x => x.Frob());        
    }
}

ノート:

ここでの問題は、過負荷解決が存在する場合のC#およびVBでのラムダ型推論が原因で発生します。ここでは、ラムダの本体が特定の型に対して意味があるかどうかをチェックすることにより、複数の型が一致する関係を解消するために、限定された形式のダックタイピングが使用されます。1つの型のみがコンパイル可能な本体になる場合は、その1つが選択されます。

ここでの危険は、クライアントコードにオーバーロードされたメソッドグループがあり、一部のメソッドが独自の型の引数を取り、他のメソッドがライブラリによって公開されている型の引数をとる可能性があることです。彼のコードのいずれかが型推論アルゴリズムに依存して、メンバーの有無のみに基づいて正しいメソッドを決定する場合、クライアントのタイプの1つと同じ名前の新しいメンバーをタイプの1つに追加すると、推論がスローされる可能性がありますオフにすると、過負荷の解決中にあいまいさが生じます。

タイプFooBarこの例では、継承やその他の方法では関係がないことに注意してください。これをトリガーするには、単一のメソッドグループでそれらを使用するだけで十分であり、これがクライアントコードで発生した場合、それを制御することはできません。

上記のサンプルコードは、これがソースレベルのブレークである(つまり、コンパイラエラーの結果)というより単純な状況を示しています。ただし、推論によって選択されたオーバーロードに他の引数があり、それがなければランク付けされない場合(たとえば、デフォルト値を持つオプションの引数、または暗黙的な引数を必要とする宣言された引数と実際の引数の間の型の不一致)、これはサイレントセマンティクスの変更になることもあります変換)。このようなシナリオでは、過負荷の解決は失敗しなくなりますが、コンパイラによって別の過負荷が静かに選択されます。ただし、実際には、メソッドシグネチャを慎重に作成して意図的に発生させない限り、このケースに遭遇することは非常に困難です。

于 2011-02-21T23:14:19.520 に答える
11

暗黙的なインターフェース実装を明示的なものに変換します。

ブレークの種類:ソースとバイナリ

影響を受ける言語:すべて

これは実際には、メソッドのアクセシビリティを変更するバリエーションにすぎません。インターフェイスのメソッドへのすべてのアクセスが必ずしもインターフェイスのタイプへの参照を介しているわけではないという事実を見落としがちなので、もう少し微妙です。

変更前のAPI:

public class Foo : IEnumerable
{
    public IEnumerator GetEnumerator();
}

変更後のAPI:

public class Foo : IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator();
}

変更前に機能し、変更後に破損するサンプルクライアントコード:

new Foo().GetEnumerator(); // fails because GetEnumerator() is no longer public
于 2009-10-30T17:31:57.617 に答える
7

明示的なインターフェイスの実装を暗黙的なものに変換します。

休憩の種類:ソース

影響を受ける言語:すべて

明示的なインターフェース実装を暗黙的なインターフェース実装にリファクタリングすることは、APIを壊す方法がより微妙です。表面的には、これは比較的安全であるように思われますが、継承と組み合わせると問題が発生する可能性があります。

変更前のAPI:

public class Foo : IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator() { yield return "Foo"; }
}

変更後のAPI:

public class Foo : IEnumerable
{
    public IEnumerator GetEnumerator() { yield return "Foo"; }
}

変更前に機能し、変更後に破損するサンプルクライアントコード:

class Bar : Foo, IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator() // silently hides base instance
    { yield return "Bar"; }
}

foreach( var x in new Bar() )
    Console.WriteLine(x);    // originally output "Bar", now outputs "Foo"
于 2009-10-30T18:10:18.617 に答える
7

フィールドをプロパティに変更する

休憩の種類:API

影響を受ける言語:Visual BasicおよびC#*

情報:通常のフィールドまたは変数をVisual Basicのプロパティに変更する場合、そのメンバーを何らかの方法で参照する外部コードを再コンパイルする必要があります。

変更前のAPI:

Public Class Foo    
    Public Shared Bar As String = ""    
End Class

変更後のAPI:

Public Class Foo
    Private Shared _Bar As String = ""
    Public Shared Property Bar As String
        Get
            Return _Bar
        End Get
        Set(value As String)
            _Bar = value
        End Set
    End Property
End Class    

動作するが後で壊れたサンプルクライアントコード:

Foo.Bar = "foobar"
于 2013-11-21T18:08:46.020 に答える
6

名前空間の追加

ソースレベルのブレーク/ソースレベルのクワイエットセマンティクスの変更

vb.Netでの名前空間解決の動作方法により、ライブラリに名前空間を追加すると、以前のバージョンのAPIでコンパイルされたVisualBasicコードが新しいバージョンでコンパイルされない場合があります。

サンプルクライアントコード:

Imports System
Imports Api.SomeNamespace

Public Class Foo
    Public Sub Bar()
        Dim dr As Data.DataRow
    End Sub
End Class

新しいバージョンのAPIで名前空間が追加されたApi.SomeNamespace.Data場合、上記のコードはコンパイルされません。

プロジェクトレベルの名前空間のインポートでは、より複雑になります。上記Imports Systemのコードから省略されているが、System名前空間がプロジェクトレベルでインポートされている場合でも、コードでエラーが発生する可能性があります。

ただし、Apiの名前空間にクラスが含まれている場合、コードはコンパイルされますがDataRow、古いバージョンのAPIでコンパイルされた場合と、新しいバージョンのAPIでコンパイルされた場合のインスタンスになります。Api.SomeNamespace.DatadrSystem.Data.DataRowApi.SomeNamespace.Data.DataRow

引数の名前変更

ソースレベルのブレーク

引数の名前を変更することは、バージョン7(?)(.Netバージョン1?)からのvb.netおよびバージョン4(.Netバージョン4)からのc#.netの重大な変更です。

変更前のAPI:

namespace SomeNamespace {
    public class Foo {
        public static void Bar(string x) {
           ...
        }
    }
}

変更後のAPI:

namespace SomeNamespace {
    public class Foo {
        public static void Bar(string y) {
           ...
        }
    }
}

サンプルクライアントコード:

Api.SomeNamespace.Foo.Bar(x:"hi"); //C#
Api.SomeNamespace.Foo.Bar(x:="hi") 'VB

参照パラメータ

ソースレベルのブレーク

1つのパラメーターが値ではなく参照によって渡されることを除いて、同じシグネチャでメソッドオーバーライドを追加すると、APIを参照するvbソースが関数を解決できなくなります。Visual Basicには、引数名が異なる場合を除いて、呼び出しポイントでこれらのメソッドを区別する方法(?)がないため、このような変更により、両方のメンバーがvbコードから使用できなくなる可能性があります。

変更前のAPI:

namespace SomeNamespace {
    public class Foo {
        public static void Bar(string x) {
           ...
        }
    }
}

変更後のAPI:

namespace SomeNamespace {
    public class Foo {
        public static void Bar(string x) {
           ...
        }
        public static void Bar(ref string x) {
           ...
        }
    }
}

サンプルクライアントコード:

Api.SomeNamespace.Foo.Bar(str)

フィールドからプロパティへの変更

バイナリレベルのブレーク/ソースレベルのブレーク

明らかなバイナリレベルのブレークに加えて、メンバーが参照によってメソッドに渡された場合、これによりソースレベルのブレークが発生する可能性があります。

変更前のAPI:

namespace SomeNamespace {
    public class Foo {
        public int Bar;
    }
}

変更後のAPI:

namespace SomeNamespace {
    public class Foo {
        public int Bar { get; set; }
    }
}

サンプルクライアントコード:

FooBar(ref Api.SomeNamespace.Foo.Bar);
于 2013-10-23T03:00:27.570 に答える
4

APIの変更:

  1. [廃止]属性を追加します(属性について言及することでこれをカバーしましたが、これはエラーとしての警告を使用する場合の重大な変更になる可能性があります)。

バイナリレベルのブレーク:

  1. タイプをあるアセンブリから別のアセンブリに移動する
  2. タイプの名前空間を変更する
  3. 別のアセンブリから基本クラスタイプを追加します。
  4. 別のアセンブリ(Class2)の型をテンプレート引数制約として使用する新しいメンバー(イベント保護)を追加します。

    protected void Something<T>() where T : Class2 { }
    
  5. クラスがこのクラスのテンプレート引数として使用されている場合に、別のアセンブリの型から派生するように子クラス(Class3)を変更します。

    protected class Class3 : Class2 { }
    protected void Something<T>() where T : Class3 { }
    

ソースレベルのクワイエットセマンティクスの変更:

  1. Equals()、GetHashCode()、またはToString()のオーバーライドの追加/削除/変更

(これらがどこに適合するかわからない)

展開の変更:

  1. 依存関係/参照の追加/削除
  2. 依存関係を新しいバージョンに更新する
  3. 「ターゲットプラットフォーム」をx86、Itanium、x64、またはanycpu間で変更する
  4. 別のフレームワークインストールでのビルド/テスト(つまり、.Net 2.0ボックスに3.5をインストールすると、.Net 2.0 SP2を必要とするAPI呼び出しが可能になります)

ブートストラップ/構成の変更:

  1. カスタム構成オプション(つまり、App.config設定)の追加/削除/変更
  2. 今日のアプリケーションではIoC/DIが多用されているため、DI依存コードのブートストラップコードを再構成および/または変更する必要があります。

アップデート:

申し訳ありませんが、これが私にとって壊れている唯一の理由は、テンプレートの制約でそれらを使用したことであることに気づきませんでした。

于 2009-10-08T17:24:14.687 に答える
3

デフォルトパラメータの使用を廃止するためのオーバーロードメソッドの追加

休憩の種類:ソースレベルの静かなセマンティクスの変更

コンパイラーは、デフォルトのパラメーター値が欠落しているメソッド呼び出しを、呼び出し側のデフォルト値を持つ明示的な呼び出しに変換するため、既存のコンパイル済みコードとの互換性が提供されます。以前にコンパイルされたすべてのコードに対して、正しいシグニチャを持つメソッドが見つかります。

一方、オプションのパラメーターを使用しない呼び出しは、オプションのパラメーターが欠落している新しいメソッドの呼び出しとしてコンパイルされるようになりました。すべてはまだ正常に機能していますが、呼び出されたコードが別のアセンブリにある場合、それを呼び出す新しくコンパイルされたコードは、このアセンブリの新しいバージョンに依存するようになります。リファクタリングされたコードが存在するアセンブリもデプロイせずに、リファクタリングされたコードを呼び出すアセンブリをデプロイすると、「メソッドが見つかりません」という例外が発生します。

変更前のAPI

  public int MyMethod(int mandatoryParameter, int optionalParameter = 0)
  {
     return mandatoryParameter + optionalParameter;
  }    

変更後のAPI

  public int MyMethod(int mandatoryParameter, int optionalParameter)
  {
     return mandatoryParameter + optionalParameter;
  }

  public int MyMethod(int mandatoryParameter)
  {
     return MyMethod(mandatoryParameter, 0);
  }

引き続き機能するサンプルコード

  public int CodeNotDependentToNewVersion()
  {
     return MyMethod(5, 6); 
  }

コンパイル時に新しいバージョンに依存するようになったサンプルコード

  public int CodeDependentToNewVersion()
  {
     return MyMethod(5); 
  }
于 2016-11-16T09:37:13.540 に答える
1

インターフェイスの名前を変更する

ちょっとした休憩:ソースとバイナリ

影響を受ける言語:ほとんどの場合、すべて、C#でテストされています。

変更前のAPI:

public interface IFoo
{
    void Test();
}

public class Bar
{
    IFoo GetFoo() { return new Foo(); }
}

変更後のAPI:

public interface IFooNew // Of the exact same definition as the (old) IFoo
{
    void Test();
}

public class Bar
{
    IFooNew GetFoo() { return new Foo(); }
}

動作するが後で壊れたサンプルクライアントコード:

new Bar().GetFoo().Test(); // Binary only break
IFoo foo = new Bar().GetFoo(); // Source and binary break
于 2012-11-19T14:46:59.870 に答える
1

拡張方式への昇格

種類:ソースレベルのブレーク

影響を受ける言語:C#v6以降(多分他の言語?)

変更前のAPI:

public static class Foo
{
    public static void Bar(string x);
}

変更後のAPI:

public static class Foo
{
    public void Bar(this string x);
}

変更前に機能し、変更後に壊れたサンプルクライアントコード:

using static Foo;

class Program
{
    static void Main() => Bar("hello");
}

詳細:https ://github.com/dotnet/csharplang/issues/665

于 2019-05-23T17:29:18.730 に答える
1

null許容型のパラメーターを使用したメソッドのオーバーロード

種類:ソースレベルのブレーク

影響を受ける言語:C#、VB

変更前のAPI:

public class Foo
{
    public void Bar(string param);
}

変更後のAPI:

public class Foo
{
    public void Bar(string param);
    public void Bar(int? param);
}

変更前に機能し、変更後に壊れたサンプルクライアントコード:

new Foo().Bar(null);

例外:呼び出しは、次のメソッドまたはプロパティ間であいまいです。

于 2019-07-18T13:02:57.097 に答える
0

Visual Studio Extension NDependは、バイナリレベルのブレークを検出するために、カテゴリAPIBreakingChangesにいくつかのルールを提供します。これらのルールは、 NDependベースラインが定義されている場合にのみ実行されます。

  • APIの重大な変更:タイプ:このルールは、ベースラインで公開されているタイプ、もう公開されていないタイプ、または削除されたタイプについて警告します。そのようなタイプを使用するクライアントコードは壊れます。
  • APIの重大な変更:メソッド:このルールは、ベースラインで公開されているメソッド、もう公開されていないメソッド、または削除されたメソッドについて警告します。このような方法を使用するクライアントのコードは壊れます。メソッドシグネチャが変更された場合、古いメソッドバージョンは削除されたと見なされ、新しいメソッドバージョンは追加されたと見なされるため、古いメソッドバージョンで重大な変更が検出されることに注意してください。
  • APIの重大な変更:フィールド:このルールは、ベースラインで公開されているフィールド、もう公開されていないフィールド、または削除されたフィールドについて警告します。このようなフィールドを使用するクライアントコードは壊れます。
  • APIの重大な変更:インターフェースと抽象クラス:このルールは、公開されているインターフェースまたは抽象クラスが変更され、新しい抽象メソッドが含まれている場合、または一部の抽象メソッドが削除されている場合に警告します。そのようなインターフェースを実装するか、そのような抽象クラスから派生するクライアントコードは壊れます。
  • 壊れたシリアル化可能なタイプ:このルールは、 SerializableAttributeでタグ付けされたタイプの壊れた変更について警告します。そのために、このルールは、ベースライン以降に追加または削除されたシリアル化可能なインスタンスフィールドを持つシリアル化可能なタイプを検索します。NonSerializedAttributeでタグ付けされたフィールドは考慮されていないことに注意してください。
  • 列挙型の変更を避けるフラグステータス:このルールは、ベースラインでFlagsAttributeでタグ付けされていた列挙型と一致し、現在は一致していません。また、 FlagsAttributeでタグ付けされ、ベースラインでタグ付けされていない、反対の列挙型とも一致します。FlagsAttributeでタグ付けされることは、列挙の強力なプロパティです。動作に関してはそれほど多くはありませんが(列挙がFlagsAttributeでタグ付けされている場合、enum.ToString()メソッドの動作のみ変更されます)、意味に関しては、列挙は値の範囲ですか、それともフラグの範囲ですか?

また、ユーザーが新しいパブリックAPI要素を参照できるようにするために3つのコードクエリが提案されています。

于 2020-08-26T08:29:44.647 に答える
0

constへの静的読み取り専用変換

種類:バイナリレベルのブレーク

影響を受ける言語:C#、VB、およびF#

変更前のAPI:

public static class Foo
{
    public static readonly string Bar = "Value";
}

変更後のAPI:

public static class Foo
{
    public const string Bar = "Value";
}

新しい変更をターゲットにするには、すべてのクライアントを再コンパイルする必要があります。そうしないと、MissingFieldExceptionがスローされます。

于 2020-11-03T14:54:48.747 に答える