【问题标题】:new keyword not forcing hiding - OOP C#新关键字不强制隐藏 - OOP C#
【发布时间】:2015-04-19 04:58:31
【问题描述】:

我有以下场景:

我想模拟一个界面,以便对我的应用进行单元测试。我试图不创建一个新的模拟类来实现我的接口,而是创建一个继承原始具体类的新类,并在调用该方法时使用 new 关键字强制执行新行为。但由于某种原因,调用的是具体类的方法,而不是我创建的类(作为模拟)

以下代码:

public interface IMyService 
{ 
    Model GetModelData(int id)
}

public class MyService : IMyService
{
    public Model GetModelData(int id)
    { 
       //call to db     
    }
}

public class MyService2 : MyService
{
    public MyService2()
        : base(new MyRepository())
    {    
    }

    public new Model GetModelData(int id)
    { 
        return new Model();
    }
}

注入依赖:

x.ForRequestedType<IMyService>().TheDefaultIsConcreteType<MyService2>();

检索具体类:在调试时我可以看到 myService 指向 MyService2 类,但该方法在 MyService 类上执行。

_myServie = ObjectFactory.GetInstance<IMyService>();
                Model modelData = _myServie.GetModelData(5);

【问题讨论】:

  • 你使用的是哪个依赖注入框架?
  • @dav_i:通过查看代码,我假设是 StructureMap。 ObjectFactory 是 StructureMap 所拥有的。
  • @Avais,请解释为什么您要创建一个派生自真实实现的模拟,而不是仅基于接口创建一个模拟。您所做的事情很脆弱,并使测试变得更加复杂。如果您需要包含实现,那么您的设计肯定有问题。
  • 是的,是结构图。 @Steven:那是因为,我不希望我的 MyService2 类实现接口 MyInterface1 上的所有方法(因为它很大)我只想模拟一种我将用于我的更改的方法(不调用存储库)
  • @Avais:你不能改变那个界面并不重要。重要的是您的应用程序代码直接依赖于它自己没有定义的接口。这是一个错误,因为根据APP&P“客户 [...] 拥有抽象接口”。因此,您应该做的是为您的应用程序制作特定的小接口,并且实现(代理)可以将调用转发到丑陋的公司范围的接口定义。不要用这种废话污染你的应用程序代码和测试代码。

标签: c# oop inheritance dependency-injection


【解决方案1】:

只需使用new 创建一个新方法,而无需将其与接口关联。您在真实代码中使用接口(我假设),因此您希望将接口方法绑定到新方法。为此,您必须声明您正在再次实现该接口。这是一个显示差异的示例:

using System;

interface IFoo
{
    void Bar();
}

class Normal : IFoo
{
    public void Bar()
    {
        Console.WriteLine("Normal.Bar");
    }
}

class Extended1 : Normal
{
    public new void Bar()
    {
        Console.WriteLine("Extended1.Bar");
    }
}

class Extended2 : Normal, IFoo
{
    public new void Bar()
    {
        Console.WriteLine("Extended2.Bar");
    }
}

class Test
{
    static void Main()
    {
        IFoo x = new Extended1();
        IFoo y = new Extended2();

        x.Bar();
        y.Bar();
    }
}

输出:

Normal.Bar
Extended2.Bar

因此,如果您将类声明更改为:

public class MyService2 : MyService, IMyService

您应该会发现它确实有效。我不能说我是这种方法的忠实拥护者,请注意 - MyService 中调用该方法的任何内容都会调用它自己的实现除非它碰巧通过 IMyService 调用-类型参考。您可以在您的具体类中将接口实现设为虚拟,然后在您的子类中覆盖它;这在某些方面会更好,但在其他方面会更糟。基本上,这种“半继承”对我来说感觉很脆弱。

我怀疑如果你有一个抽象基类,你的真实实现和测试实现都派生自...

【讨论】:

  • 啊,在没有重新声明的情况下,new MyService() is IMyServicenew MyService2() is IMyService 有点棘手。有趣的角落案例。
  • 但是我将不得不实现我想要避免的所有 IMyService 接口方法。有什么办法让我只能模拟该接口的一种方法吗?谢谢
  • @Avais:不,您不需要重新实现所有这些方法。任何你不重新实现的都只会使用基类中的现有实现。
  • 谢谢大家,这行得通 :) @JonSkeet:谢谢伙计,是的,我不需要重新实现我打算隐藏的接口方法 :) 我很高兴。干杯
【解决方案2】:

我认为您正在寻找的是使 MyService 上的方法虚拟并在 MyService2 中覆盖它。像这样:

public interface IMyService 
{ 
    Model GetModelData(int id)
}

public class MyService : IMyService
{
    public virtual Model GetModelData(int id)
    { 
       //call to db     
    }
}

public class MyService2 : MyService
{
    public MyService2()
        : base(new MyRepository())
    {    
    }

    public override Model GetModelData(int id)
    { 
        return new Model();
    }
}

这样,如果子类中的方法被覆盖,那么子类方法会被调用,否则基类会消耗方法调用。

【讨论】:

  • IMyService 是具有更多方法的业务部分。我只想模拟“GetModeldata”方法,而不必在我的新“模拟”类上实现接口。有什么办法吗?谢谢
  • 就像我说的,如果你从一个类继承,而不仅仅是你的接口,在你的基类上让它成为虚拟的。在您的新类中,只需覆盖一个方法,所有其他方法将与基类相同。您将能够以这种方式测试这个单一的方法。
猜你喜欢
  • 1970-01-01
  • 2012-06-12
  • 1970-01-01
  • 1970-01-01
  • 2011-12-28
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
相关资源
最近更新 更多