2012-01-18 15 views
7

私はC#インターフェイスとそのインターフェイスを実装する具象クラスを持っています。私は今、そのインタフェースを実装する別のクラスを作成したいと思っています。十分に簡単です。C#インターフェイスクラスとベースクラス

しかし、ほとんどのメソッドはクラス内で全く同じになり、実際には2つのメソッドだけが実際に変更されます。

私の最初のクラスに含まれる2番目のクラスのロジックをすべて複製したくありません。

第2クラスを作成するにはどうすればいいですか?余分なものを除いて、ファーストクラスのロジックを使用しますか?

私のインターフェイスはIEventRepositoryと呼ばれ、私の第1クラスはBaseEventsと呼ばれます。 FooBarEventsという新しいクラスを作成したいと思います。 FooBarEventsため

マイクラス定義は次のとおり

public class FooBarEvents : BaseEvents, IEventRepository 

私の意図は、コードを複製し、各方法におけるリターンbase.Method()を使用することでした。

これは間違っていると思いますか?

+0

なぜインターフェイスを使用しているのですか? –

答えて

10

FooBarEventsは、BaseEventsから継承する必要があります。IEventRepositoryも実装していないため、BaseEventsは既にインターフェイスを実装しています。一部のIEventRepositoryメソッドの動作をFooBarEventsに変更する必要がある場合は、それらのメソッドをオーバーライドするだけです。

編集:いくつかの例

interface IEventRepository 
{ 
    void CommonMethodA(); 
    void CommonMethodB(); 
    void ImplentationSpecificMethod(); 
} 

abstract class BaseEvents : IEventRepository 
{ 
    public void CommonMethodA() 
    { ... } 

    public virtual void CommonMethodB() 
    { ... } 

    public abstract void ImplementationSpecificMethod(); 

    public void BaseEventsMethod() 
    { ... } 

    public void BaseEventsMethod2() 
    { ... } 
} 

class FooBarEvents : BaseEvents 
{ 
    public override void CommonMethodB() 
    { 
     // now FooBarEvents has a different implementation of this method than BaseEvents 
    } 

    public override void ImplementationSpecificMethod() 
    { 
     // this must be implemented 
    } 

    public new void BaseEventsMethod2() 
    { 
     // this hides the implementation that BaseEvents uses 
    } 

    public void FooBarEventsMethod() 
    { 
     // no overriding necessary 
    } 
} 

// all valid calls, assuming myFooBarEvents is instantiated correctly 
myFooBarEvents.CommonMethodA() 
myFooBarEvents.CommonMethodB() 
myFooBarEvents.BaseEventsMethod(); 
myFooBarEvents.BaseEventsMethod2(); 
myFooBarEvents.FooBarEventsMethod(); 
myFooBarEvents.ImplementationSpecificMethod(); 

// use the contract thusly: 
void DoSomethingWithAnEventRepository(BaseEvents events) 
{ ... } 
+0

私はこれを取得しますが、FooBarEventsクラスはクライアント固有のものであり、BaseEventsに実装されていない別の10個のメソッドを持つ場合があります(固有です)。 BaseEventsが10のメソッドをすべて仮想として持ち、何もしないで、実装されていない例外や無効な操作例外を投げるのは悪い習慣ではないでしょうか? – Paul

+0

私はあなたが何を求めているのか分かりません。あなたは 'FooBarEvents'に10個のクライアント固有のメソッドを追加しますが、それらをオーバーライドするために' BaseEvents'にそれらのイベントのシグネチャを追加しなければならないと言っていますか?そうではありません。実装を 'FooBarEvents'に直接追加することができます。私は私の答えを編集し、例を追加します。 –

+0

これらのシグネチャをBaseEventsに追加しないと、BaseEventsが特定のインターフェイスメンバーを実装していないというエラーが表示されます。私は依存関係注入を使用しているので、FooBarEventsクラスで必要なメンバのインタフェースにコントラクトを追加する必要があります。 – Paul

6

BaseEventsは既にIEventRepositoryを実装しているため、FooBarEventsに再度実装する必要はありません。 FooBarEventsは自動的にBaseEvents 'の実装を継承します。

2

あなたの第2クラスをファーストクラスにすることができます。最初のクラスは抽象クラスにすることができますが、インターフェイスからの一般的なメソッドのみを実装します。

+0

「あなたの第二のクラスはあなたの第二のクラスを拡張することができます」 - あなたは「あなたのファーストクラスを拡張する」という意味ですか? –

+0

はい、申し訳ありません - あなたは正しいサミュエルです –

+0

私は抽象クラスについて知りたくないNinject依存性注入を使用しています。 – Paul

0

IEventRepositoryBaseEvents実装における方法の特定の選択はは常に同じ実装を維持しようとしている場合は、あなただけのBaseEventsクラスでそれらを実装してマークすることができますと変更されたものがvirtualとなります。そうすれば、FooBarEventsがメソッドの1つの実装を変更したい場合、単にそれをオーバーライドできます。

あなたのFooBarEventsクラスにIEventsRepositoryを追加することに関するちょっとした注意:これは有効です。 Jon Skeetの回答については、hereを参照してください。

3

基本クラスのメソッドをVirtualと定義して、子クラスで変更するものをに変更するとどうでしょうか?

2

利用の継承:

public interface IFoo 
{ 
    void GeneralBehaviorMethod1(); 
    void GeneralBehaviorMethod2(); 
    void SpecificBehaviorMethod1(); 
} 

public class Bar: IFoo 
{ 
    public void GeneralBehaviorMethod1() {...} 
    public void GeneralBehaviorMethod2() {...} 

    public virtual void SpecificBehaviorMethod1() {...} 
    ... 
} 

public class BarOnSteroids: Bar 
{ 
    public override void SpecificBehaviorMethod1() {...} 
} 

BarOnSteroidsBarの全ての動作を継承し、あなたは、あなたが(彼らは基本クラスの仮想としてマークする必要がBarOnSteroidsでそれらをオーバーライドすることによって、必要な任意の方法の特定の動作を変更することができますBar)。

この方法では、あなたは以下を持っているでしょう:

IFoo iFoo = new Bar(); 
iFoo.SpecificBehaviorMethod1(); //Bar implementation will be called; 

IFoo iFoo = new BarOnSteroids(); 
iFoo.SpecificBehaviorMethod1(); //BarOnSteroids implementation will be called. 
iFoo.CommonBehaviorMethod1(); //Bar implementation will be called. 

Bar bar = new BarOnSteroids(); 
bar.SpecificBehaviorMethod1(); //BarOnSteroids implementation will be called. 
bar.CommonBehaviorMethod1(); //Bar implementation will be called. 

これは、あなたがIFooインターフェイスの一部である方法の特定の動作を変更したいを前提としています。 BarOnSteroidsに機能を追加するだけであれば、フォームBarを継承してその機能を継承し、新しい機能を実装するために必要なすべての新しいメソッドを追加するだけです。

+0

もし私がIFooをBarを使って消費していて、SpecificBehaviourMethod1を呼び出せば、BarOnSteroidsがBarの何かをしているかのように見えるでしょうか? – Paul

+0

@Pual。 'SpecificBehaviorMethod''は、' SpecificBehaviorMethod''を実装しなければなりません。 'SpecificBehaviorMethod'が仮想である場合には、呼び出すインスタンスの実際のタイプに固有の実装を呼び出します。 – InBetween

3

次のコードは、抽象基底クラスでいくつかのインターフェイスメソッドの共通実装を提供し、他のインターフェイスのカスタム実装を提供する方法を示しています。

public interface IEventRepository 
{ 
    void Method1(); 
    void Method2(); 
} 

public abstract class BaseEvents : IEventRepository 
{ 
    public void Method1() 
    { 
    Console.WriteLine("This is shared functionality"); 
    } 

    public abstract void Method2(); 
} 

public class Implementation1 : BaseEvents 
{ 
    override public void Method2() 
    { 
    Console.WriteLine("Impl1.Method2"); 
    } 
} 

public class Implementation2 : BaseEvents 
{ 
    override public void Method2() 
    { 
    Console.WriteLine("Impl2.Method2"); 
    } 
} 

public class Program 
{ 
    static void Main(string[] args) 
    { 
    var implementations = new List<IEventRepository> { new Implementation1(), new Implementation2() }; 

    foreach (var i in implementations) 
    { 
     Console.WriteLine(i.GetType().Name); 
     Console.Write("\t"); 
     i.Method1(); // writes 'This is shared functionality' 

     Console.Write("\t"); 
     i.Method2(); // writes type specific message 
    } 
    } 

}

+0

この場合の明示的なインターフェイス実装の宣言?私はIEventRepository.Method2(){}のようなものを意味します。 – remio

+0

確かに、私は明示的なインタフェースの価値を実際に理解していない – Jason

+0

私の見解では、クライアントクラスが基礎となる実装を忘れるのを助けることで型を強制します。 – remio

0

いくつかの異なるアプローチがあります。

1。インタフェースを完全にスキップし、抽象クラスにします。それは動作しますが、あなたが唯一の基本クラスを持つことができるという事実は、

public abstract class EventRepository 
{ 
    public abstract int MustBeOverridden(string str);//classes have to override this 
    public virtual int CanBeOverridden(int i)//classes can override but may choose not to. 
    { 
    return 4; 
    } 
    public int CannotOverride(string str)//this is always the same 
    { 
    return MustBeOverridden(str) + 3;//can make use of this 
    } 
} 

あなたは一つのクラスがインタフェースを実装することができますC#で使用を制限するとき、これは単純であり、もう一つはそれから派生:

public interface IEventRepository 
{ 
    int Method1(string str); 
    int Method2(string str); 
} 

public class EventClass1 : IEventRepository 
{ 
    public int Method1(string str)//can't be overridden as not marked virtual 
    { 
    return 1; 
    } 
    public virtual int Method2(string str)//can be overridden 
    { 
    return 2; 
    } 
} 

public class EventClass2 : EventClass1 
{ 
    public override int Method2(string str) 
    { 
    return -2; 
    } 
} 

はそれらを持って、両方のいくつかの一般的な動作を与える抽象クラス上書き:

public abstract class EventClass : IEventRepository 
{ 
    public abstract int Method1(string str); 
    public int Method2(string str) 
    { 
    return 2; 
    } 
} 

public class EventClass1 : EventClass 
{ 
    public override int Method1(string str) 
    { 
    return 1; 
    } 
} 
public class EventClass2 : EventClass 
{ 
    public override int Method1(string str) 
    { 
    return -1; 
    } 
} 

彼らはまた、階層とは何の関係もない、静的なヘルパークラスを使用しますが、可能性を機能の実装に役立つメソッドを提供します。

は、このパターンのかの注意が必要:IEventRepository.Method1がより賢明に定義されている場合でも

public class EventClass1 : IEventRepository 
{ 
    public int Method1(string str)//not override-able 
    { 
    return 1; 
    } 
    public int Method2(string str)//not override-able 
    { 
    return 2; 
    } 
} 
public class EventClass2 : EventClass1, IEventRepository 
{ 
    //We really want our own Method1! 
    public new int Method1(string str) 
    { 
    return 3; 
    } 
    int IEventRepository.Method1(string str) 
    { 
    return -1; 
    } 
} 

EventClass2 e2 = new EventClass2(); 
EventClass1 e1 = e2; 
IEventRepository ie = e2; 
Console.WriteLine(e2.Method1(null));//3 
Console.WriteLine(e1.Method1(null));//1 
Console.WriteLine(ie.Method1(null));//-1 

、上記のは混乱を招く可能性があります。

関連する問題