如何使用扩展方法完成接口

时间:2017-01-04 15:35:24

标签: c# inheritance extension-methods

给定一个接口IFoo

interface IFoo {
    void Do();
    void Stuff();
}

假设有(遗留)类Foo1,Foo2,Foo3都实现了IFoo。

可以通过使用IFoo的某些方法来完成填充,或者对于较新的类,只需使用DoStuff()即可。实际上,人们可能会把它看作好像DoStuff()被遗忘了#34;在IFoo。

还有更新的类FooX(FooY,...)实现IFoo2,另外还有一个方法DoStuff();

 interface IFoo2 : IFoo {
        void DoStuff();
   }

我需要接受IFoo对象,并且能够" Do Stuff"在上面。

 //Let us assume foos = new IFoo[] {new Foo1(), new Foo2(), new Foo3(), new FooX()};

 void MyMethod(IFoo[] foos){
     foreach(foo in foos){
        //DoStuff is not defined in IFoo
        foo.DoStuff();
     }
 }

所以,我想在IFoo上为遗留类

定义一个扩展方法DoStuff()
public static DoStuff(this IFoo self){
    self.Do();
    self.Stuff();
}

不幸的是,即使对于FooX,也始终会调用此扩展方法。

我可以做类似

的事情
public static DoSomeStuff(this IFoo self){
    if(self is IFoo2) {
        (self as IFoo2).DoStuff()
    } else {
       self.Do();
       self.Stuff();
    }
}

void MyMethod(IFoo[] foos){
     foreach(foo in foos){            
        foo.DoSomeStuff();
     }
 }

但是,MyMethod方法驻留在遗留项目中,目前还不知道IFoo2。是否可以在不使用IFoo2的情况下找到解决方案?

4 个答案:

答案 0 :(得分:2)

你不应该扩展IFoo接口。它是休息Interface Segregation principle

如果这些对象在代码中表示完全相同的实体,则不应为它们使用不同的接口。 如果您想要实现接口IFoo的类的扩展功能,但是不创建表示相同合同的第二个接口,则可以创建扩展方法。但是,如果您想更改IFoo合同 - 重构遗留对象(添加缺少的实现)。

答案 1 :(得分:0)

只要您的变量的类型为IFoo,就会调用扩展方法DoStuff。解决这个问题的常用方法正是您在上一段中提出的建议,或者确保您在需要调用较新接口方法的地方使用IFoo2而不是IFoo

答案 2 :(得分:0)

您可以创建一个抽象子类,该子类为当前未实现它的类实现Do和Stuff方法。

public abstract class abstractFoo : IFoo 
{
    public virtual void Do() {}
    public virtual void Stuff(){}
}

如果可以继承这个抽象类

public class Foo: IFoo 
{
    // interface implementation required
}

becomes:

public class Foo: abstractFoo
{
    // interface implementation NOT required
}

答案 3 :(得分:0)

恕我直言FooX不应该开始实施IFoo,并且应该重新考虑当前的建筑。

那说,并且不知道你正在对抗的确切限制,你能通过包装器发送IFooX吗?如下所示:

public class FooXWrapper<T>: IFoo where T: FooX
{
    readonly T foo;
    bool doCalled;

    public FooWrapper(T foo)
    {
        this.foo = foo;
    }

    public void Do()
    {
        doCalled = true;
    }

    public void Stuff()
    {
         if (!doCalled)
             throw new InvalidOperationException("Must call Do");

         foo.DoStuff();
    }
}

这是一个丑陋的黑客,但考虑到情况......