C#接口和基类

本文关键字:基类 接口 | 更新日期: 2023-09-27 18:20:35

我有一个C#接口,以及一个实现该接口的具体类。我现在想创建另一个实现该接口的类。很简单。

然而,类中的大多数方法都是完全相同的,只有少数方法会发生实际更改。

我不想重复我的第二类中包含在第一类中的所有逻辑。

我如何创建第二个类,并使用第一个类中的逻辑,除了额外的东西?

我的接口叫做IEventRepository,我的第一个类叫做BaseEvents。我现在想创建一个名为FooBarEvents的新类。

我对FooBarEvents的类定义是:

public class FooBarEvents : BaseEvents, IEventRepository

我的意图是使用返回基地。方法()。

我想这是不对的?

C#接口和基类

FooBarEvents应该只需要从BaseEvents继承,而不需要实现IEventRepository,因为BaseEvents已经实现了接口。如果需要更改FooBarEvents中某些IEventRepository方法的行为,只需覆盖这些方法即可。

编辑:的一些例子

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

由于BaseEvents已经实现了IEventRepository,因此不需要在FooBarEvents中再次实现它。FooBarEvents自动继承BaseEvents的实现。

下面的代码展示了如何用抽象基类提供一些接口方法的通用实现,并为其他接口方法提供自定义实现。

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

}

为什么不将基类中的方法定义为Virtual,并覆盖要在子类中更改的方法?

您可以使第二个类扩展第一个类。第一个类可以是抽象的,但只能实现接口中的通用方法。

使用继承:

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将继承Bar的所有行为,并且您可以通过在BarOnSteroids中重写所需的任何方法来更改它们的特定行为(它们需要在基类Bar中标记为virtual)。

这样你就会有以下内容:

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即可继承其所有功能,并添加实现新功能所需的所有新方法。

有几种不同的方法。

一个。完全跳过接口,使其成为一个抽象类。当它工作时,这会更简单,但事实上,你只能有一个基类限制了在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
  }
}

您可以让一个类实现接口,另一个类从中派生:

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

他们还可能使用一个静态帮助器类,该类与层次结构无关,但它确实提供了在实现功能时有用的方法。

不过要警惕这种模式:

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

即使IEventRepository.Method1的定义更合理,上述内容也可能导致混淆。

如果IEventRepositoryBaseEvents实现中的某些方法选择总是保持相同的实现,那么您可以在BaseEvents类中实现它们,并将可能更改的方法标记为virtual。这样,如果FooBarEvents希望更改其中一个方法的实现,它可以简单地覆盖它

关于将IEventsRepository添加到FooBarEvents类,请注意:这样做是有效的。请参阅此处获取Jon Skeet对此的回答。