web-dev-qa-db-ja.com

C#インターフェイスとオプションのメソッド

インターフェイスはコントラクトであり、変更(追加も含む)は依存するコードを壊すことを理解しています。しかし、最近の.NETバージョン(3、3.5 ??)の1つが新しいインターフェイスメンバーに適用できる新しい属性を追加したことをしばらく前に読んだと誓ったかもしれません。この属性により、バージョニングやメンバーをオプションにすることができます。それは次のようなものでした:

interface ITest
{
    void MethodOne();

    [InterfaceVersion(2)]
    void MethodTwo();
}

私はこれのために高低を見ましたが、それを見つけることができないようです。私が読んだと思うことを単に誤解しているだけで、そのようなことはないのではないかと思っています。誰か洞察力がありますか?

39

次の2つのインターフェースを作成する必要があります。

interface ITest
{
    void MethodOne();
}

interface ITest2 : ITest
{
    void MethodTwo();
}

これにより、どの機能がどのバージョンのインターフェイスを必要とするかが明確になるため、インターフェイスを実装するクラスが1つだけ、または両方のメソッドを実装しているかどうかを確認する必要がありません。

49

私はそのような属性を見たことがありませんが、それは可能だと思います。 この記事 MSDNでは、overridesおよびnewキーワードの使用によるバージョン管理について説明しています。

つまり、C#には、派生クラスを進化させ、互換性を維持できる言語機能が備わっています。この例は、純粋にベースから派生した関係を示していますが、ベースは実際に、バージョン管理に必要なインターフェースを実装します。 1つのインターフェースに別の(以前のバージョン)インターフェースが必要な場合、このメソッドと組み合わせて使用​​すると非常に便利です。

別のインターフェースを作成する例:

public interface IMyInterface
{
  void FirstMethod();
}

public interface IMySecondInterface : IMyInterface
{
  void SecondMethod();
}

互換性を維持するために継承を使用する例:

public class MyBase 
{
   public virtual string Meth1() 
   {
      return "MyBase-Meth1";
   }
   public virtual string Meth2() 
   {
      return "MyBase-Meth2";
   }
   public virtual string Meth3() 
   {
      return "MyBase-Meth3";
   }
}

class MyDerived : MyBase 
{
   // Overrides the virtual method Meth1 using the override keyword:
   public override string Meth1() 
   {
      return "MyDerived-Meth1";
   }
   // Explicitly hide the virtual method Meth2 using the new
   // keyword:
   public new string Meth2() 
   {
      return "MyDerived-Meth2";
   }
   // Because no keyword is specified in the following declaration
   // a warning will be issued to alert the programmer that 
   // the method hides the inherited member MyBase.Meth3():
   public string Meth3() 
   {
      return "MyDerived-Meth3";
   }

   public static void Main() 
   {
      MyDerived mD = new MyDerived();
      MyBase mB = (MyBase) mD;

      System.Console.WriteLine(mB.Meth1());
      System.Console.WriteLine(mB.Meth2());
      System.Console.WriteLine(mB.Meth3());
   }
}
10
Kilhoffer

C#4の新しい "no pia"機能について考えていますか?つまり、PIAから実際に使用するインターフェイスの一部のみを「リンク」することができ、PIAを顧客に出荷することをスキップできます。その後、いくつかの異なるアセンブリでこれを数回実行すると、CLRは、リンクされたすべての部分インターフェイスが論理的に同じタイプであることを理解し、それらを統合します。このようにして、インターフェイスの各フレーバーを実装するオブジェクトを1つのアセンブリから別のアセンブリに渡すことができ、すべてが機能します。ただし、「no pia」インターフェースの作成元であるoriginalインターフェースは同じである必要があります。

6
Eric Lippert

インターフェイスの実装を部分的に実装できるような属性はありません。ただし、抽象クラスを使用してこれを回避できます。

public abstract class Test
{
     public abstract void MethodOne();
     public virtual void MethodTwo() { }
}

これにより、ユーザーは、MethodOneのオーバーライドを強制しながら、Testから継承するときにMethodTwoをオーバーライドするかどうかを決定できます。

5
David Morton

.NETフレームワークにはそのような属性はありません。

5
Jorge Córdoba

2019の更新:プロジェクトがC#8.0をサポートしている場合は、「デフォルトのインターフェース実装 を使用できます。 = "。これにより、メソッドの実装がオプションになり、実装しないことを選択した場合はデフォルトの実装にフォールバックします。

interface ITest
{
    void MethodOne();

    public void MethodTwo()
    {
       //Empty default implementation
    }
}
3
Leon Lucardie

私は最近、多重継承の欠如が命令されて、既存のインターフェースを抽象クラスに変換することを禁止する状況にあり、拡張ソリューションで自分自身を見つけました:

    interface IFoo {
            int RowCount();
    }

    static class _FooExtensions {
            public static bool HasAnyRows (this IFoo foo) {
                    return foo.RowCount() > 0;
            }
    }

これにより、他の関数でabstractメソッドを定義できる場合に備えて、デフォルトのバージョンを提供できます。

2
Sebastian Mach

あなたは次のようなものを読んだかもしれません

 interface ITest
{
    void MethodOne();

    [InterfaceVersion(2)]
    void MethodTwo();
}



[AttributeUsage(AttributeTargets.All)]
public class InterfaceVersion : System.Attribute
{
    public readonly int N;

    public InterfaceVersion(int n) 
    {
        this.N = n;
    }
}

しかし、それがMethodTwoの実装をオプションにすることはできないと思います。

編集:

コードを実行したところ、実際にMethodTwoの実装がオプションにならないことがわかりました。

1
Pratik Deoghare