Question

I have a C# interface, and a concrete class that implements that interface. I now want to create another class that implements that interface. Simple enough.

However, most methods will be exactly the same in the classes, and only a couple of methods will actually change.

I don't want to duplicate all of the logic in my 2nd class that is contained in my first.

How do I create the 2nd class, and use the logic in my first class except for the extra stuff?

My interface is called IEventRepository, and my 1st class is called BaseEvents. I now want to create a new class called FooBarEvents.

My class definition for FooBarEvents is:

public class FooBarEvents : BaseEvents, IEventRepository

My intention was to then use the return base.Method() in each method that duplicates the code.

I'm assuming this isn't correct?

Was it helpful?

Solution

FooBarEvents should only need to inherit from BaseEvents, not also implement IEventRepository, as BaseEvents already implements the interface. If you need to change the behavior of some IEventRepository methods in FooBarEvents, just override those methods.

Edit: some examples

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)
{ ... }

OTHER TIPS

Since BaseEvents already implements IEventRepository, you don't need to implement it again in FooBarEvents. FooBarEvents automatically inherits BaseEvents' implementation.

Why don't you define your methods in the base class as Virtual and override the ones that you want to change in the child class?

The following code shows how to provide a common implementation of some interface methods with an abstract base class, and provide custom implementations for others.

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
    }
  }

}

You can make your second class extend your first class. Your first class can be abstract but only implement the common methods from the interface.

Use inheritance:

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() {...}
}

BarOnSteroids will inherit all behavior of Bar and you can alter the specific behavior of any methods you need by overriding them in BarOnSteroids (they need to be marked as virtual in the base class Bar).

This way you would have the following:

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.

This assumes you want to change specific behavior of methods that are part of the IFoo interface. If all you want is to add additional functionality to BarOnSteroids then simply inherit form Bar to inherit all it's functionality and add all required new methods to implement the new functionality.

If a certain selection of methods in the BaseEvents implementation of IEventRepository are always going to maintain the same implementation, then you can just implement them in the BaseEvents class and mark the ones that might change as virtual. That way, if FooBarEvents wishes to change the implementation of one of the methods, it can simply override it.

Just a note with regards to adding IEventsRepository to your FooBarEvents class: it is valid to do that. See here for a Jon Skeet answer about it.

There's a few different approaches.

One. Skip the interface entirely, and make it an abstract class. This is simpler when it works, but the fact that you can only have one base class restricts use in C#

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
  }
}

You can have one class implement the interface, and another derive from it:

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;
  }
}

Have them both override an abstract class that gives some common behaviour:

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;
  }
}

They might also use a static helper class that has nothing to do with the hierarchy, but which does provide methods that are useful in implementing the functionality.

Be wary though of this pattern:

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

Even when IEventRepository.Method1 is defined more sensibly, the above is likely to lead to confusion.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top