35

次の例を考えてみましょう。

interface IBase1
{
   int Percentage { get; set; }
}

interface IBase2
{
   int Percentage { get; set; }
}

interface IAllYourBase : IBase1, IBase2
{
}

class AllYourBase : IAllYourBase
{
   int percentage;

   int Percentage {
      get { return percentage; }
      set { percentage = value; }
   }
}

void Foo()
{
   IAllYourBase iayb = new AllYourBase();
   int percentage = iayb.Percentage; // Fails to compile. Ambiguity between 'Percentage' property.
}

Percentage上記の例では、呼び出すプロパティの間にあいまいさがあります。IBase1およびIBase2インターフェースが変更されない可能性があると仮定すると、このあいまいさを最もクリーンで最も好ましい方法で解決するにはどうすればよいでしょうか。

アップデート

明示的なインターフェイス実装を使用して得た応答に基づいて、これは問題を解決しますが、AllYourBaseオブジェクトをIAllYourBaseほとんどの場合、決してIBase1またはIBase2。これは主IAllYourBaseに、によって実装されているインターフェイスメソッド(関連性がないと思ったため、上記のコードスニペットで詳細を説明できなかった)があり、AllYourBaseそれらにもアクセスしたいためです。常に前後にキャストすると、非常に面倒になり、コードが乱雑になります。

Percentage私は、明示的なインターフェイス実装を使用せずにプロパティを定義することを含む1つの解決策を試しましIAllYourBaseた。これにより、少なくともコンパイラエラーが解消されたようです。

class IAllYourBase : IBase1, IBase2
{
   int Percentage { get; set; }
}

これは有効な解決策ですか?

4

9 に答える 9

23

明示的に実装します。

public class AllYourBase : IBase1, IBase2
{
    int IBase1.Percentage { get{ return 12; } }
    int IBase2.Percentage { get{ return 34; } }
}

これを行うと、もちろん、あいまいでないプロパティを通常のように扱うことができます。

IAllYourBase ab = new AllYourBase();
ab.SomeValue = 1234;

ただし、パーセンテージプロップにアクセスする場合、これは機能しません(アクセスしたとすると、どの値が見返りに期待されますか?)

int percent = ab.Percentage; // Will not work.

返すパーセンテージを指定する必要があります。そして、これは正しいインターフェースにキャストすることによって行われます:

int b1Percent = ((IBase1)ab).Percentage;

あなたが言うように、あなたはインターフェースでプロパティを再定義することができます:

interface IAllYourBase : IBase1, IBase2
{
    int B1Percentage{ get; }
    int B2Percentage{ get; }
}

class AllYourBase : IAllYourBase 
{
   public int B1Percentage{ get{ return 12; } }
   public int B2Percentage{ get{ return 34; } }
   IBase1.Percentage { get { return B1Percentage; } }
   IBase2.Percentage { get { return B2Percentage; } }
}

これで、代わりに個別の名前であいまいさを解決しました。

于 2011-08-16T15:37:30.587 に答える
12

両方のプロパティがパーセントメンバー変数にアクセスする必要があると仮定すると、明示的なインターフェイスの実装とIAllYouBaseインターフェイスの拡張を使用してこれを実現できます。

interface IAllYourBase : IBase1, IBase2
{
    new int Percentage { get; set; }
}

class AllYourBase : IAllYourBase
{
   int percentage;

   public int Percentage {
      get { return percentage; }
      set { percentage = value; }
    }

    int IBase1.Percentage {
      get { return percentage; }
      set { percentage = value; }
    }

    int IBase2.Percentage {
      get { return percentage; }
      set { percentage = value; }
   }
}

それはきれいではありませんが、それはあなたがあなたが求めていると思う行動をあなたに与えるでしょう。

于 2011-08-16T15:49:30.883 に答える
10

インターフェイスを明示的に実装します。

明示的なインターフェイスメンバーの実装は、完全に修飾されたインターフェイスメンバー名を参照するメソッド、プロパティ、イベント、またはインデクサーの宣言です。

詳細なチュートリアルについては、このMSDNページを参照してください。

interface AllYourBase : IBase1, IBase2
{
   int IBase1.Percentage { get; set; }
   int IBase2.Percentage { get; set; }
}
于 2011-08-16T15:37:18.947 に答える
7

明示的に実装してアクセスします。

interface IAllYourBase : IBase1, IBase2 { } 
public class AllYourBase : IAllYourBase
{     
      int IBase1.Percentage { get{ return 12; } }     
      int IBase2.Percentage { get{ return 34; } } 
} 

IAllYourBase base = new AllYourBase();    
int percentageBase1 = (base as IBase1).Percentage;
int percentageBase2 = (base as IBase2).Percentage;
于 2011-08-16T15:37:51.457 に答える
7

プロパティに実際に異なる値を返す必要がない場合はPercentage、「マスター」インターフェイスではなく、各インターフェイスから個別に「派生」することで、コンパイラエラーを排除できます。

public class AllYourBase : IBase1, IBase2
{
    // No need to explicitly implement if the value can be the same
    public double Percentage { get { return 12d; } }
}

もちろん、個別の値が必要な場合は、インターフェイスを明示的に実装し、適切に型指定された参照を介してプロパティアクセスする必要があります。

public class AllYourBase : IBase1, IBase2
{
    // No need to explicitly implement if the value can be the same
    public double IBase1.Percentage { get { return 12d; } }
    public double IBase2.Percentage { get { return 34d; } }

}

そしてコード:

public void SomeMethod()
{
    AllYourBase ayb = new AllYourBase();
    IBase1 b1 = ayb
    double p1 = b1.Percentage;

    IBase2 b2 = ayb;
    double p2 = b2.Percentage;
}

インターフェイスを明示的に実装する際の重要な考慮事項の1つは、AllYourBaseそれ自体にプロパティがないことPercentageです。インターフェイスの1つとして入力された参照を介してオブジェクトにアクセスする場合にのみアクセスできます。

public void SomeMethod()
{
    AllYourBase ayb = new AllYourBase();
    double d = ayb.Percentage;   // This is not legal
}

更新IBase1:編集内容を見ると、との動作が異なる必要がないと仮定すると、ソリューションは問題ありませんIBase2。ソリューションはこれらのプロパティを非表示にするため、オブジェクトをこれら2つのインターフェイスのいずれかにキャストすることによってのみアクセスできます。

于 2011-08-16T15:44:02.933 に答える
7

あなたはすでに答えを受け入れましたが。明示的な実装では冗長な作業が多すぎると主張します(あなたの場合、同じプロパティを2回実装します)。

インターフェイスをさらに分離するのはどうですか(Inteface Segregation Principle)?

  internal interface IPercentage
    {
        int Percentage { get; set; }
    }

    internal interface IBase1 : IPercentage
    {
    }

    internal interface IBase2 : IPercentage
    {
    }

    internal interface IAllYourBase : IBase1, IBase2
    {
    }

    internal class AllYourBase : IAllYourBase
    {
        private int percentage;

        public int Percentage
        {
            get { return percentage; }
            set { percentage = value; }
        }

        void Foo()
        {
            IAllYourBase iayb = new AllYourBase();
            int percentage = iayb.Percentage; // Compiles now!!!
        }
    }
于 2012-03-09T08:35:30.727 に答える
3

みんなが言及した明示的な実装は明らかに正しいですが、正気のためだけに次のシナリオを検討してください(または将来あなたのコードを読む人のためだけにそれを行ってください):

これらのパーセンテージがインターフェースによって異なる意味を持つ場合は、意味のある名前を付けてみませんか?

interface IBase1 
{ 
    int PercentageBase1 { get; set; } 
}

interface IBase2
{
    int PercentageBase2 { get; set; } 
}

一方、それらが同じ意味を持っている場合は、インターフェイスの1つに1つのパーセンテージだけを持ち、別のインターフェイスから1つだけ派生させてはどうでしょうか。

interface IBase1 
{ 
    int Percentage { get; set; } 
}

interface IBase2 : IBase1
{
}

ただし、理由が何であれ最後の操作が不可能な場合は、両方のプロパティを含むベースインターフェイスを作成することを検討してください。

interface IBase0
{
    int Percentage { get; set; } 
}

interface IBase1 : IBase0
{ 
}

interface IBase2 : IBase0
{
}
于 2011-08-16T15:57:26.453 に答える
3

インターフェイスでプロパティを定義できIAllYourBaseます。

このようなもの :

interface IAllYourBase : IBase1, IBase2
{
   new int Percentage { get; set; }
}

これにより、プロパティ間のあいまいさに関する問題が解決されます。そして、あなたはインターフェースの構造を保つことができます。

于 2017-06-16T11:35:51.037 に答える
1
void Foo()
{
   IAllYourBase base = new AllYourBase();
   int percentage = base.Percentage; // Fails to compile. Ambiguity between 'Percentage' property.
}

この例baseでは、オブジェクト名にキーワードを使用しているため、問題が発生している可能性があります。

于 2011-08-16T15:42:55.933 に答える