.NET工具:提取接口并实现包装器类

8

有没有一种工具可以为现有类生成接口并生成接口?

我知道Visual Studio可以为现有类提取接口。但是,我还想生成一个实现该功能的包装器类。

我相信这对单元测试非常有帮助。

现有类示例:

public class ThirdPartyClass
{
   public void Method1(){}
   public void Method2(){}
}

这可以通过Visual Studio(提取接口)生成:
public interface IThirdPartyClass
{
   void Method1();
   void Method2();
}

我希望能更进一步:

public class ThirdPartyClassWrapper : IThirdPartyClass
{
   private tpc = new ThirdPartyClass();
   public void Method1()
   {
       tpc.Method1();
   }
   public void Method2()
   {
       tpc.Method2();
   }
}

更新:

这对于静态类尤其有用。正如Morten所指出的那样,我可以使用存根,但是如果可能的话,我希望分解我的耦合。


1
有关此问题的任何解决方案吗? - Kiquenet
在这里寻找完全相同的答案。我正在投票支持这个问题。 - Pilo
再次点赞。EF或VS应该有这个选项。 - NoobDeveloper
5个回答

8
找到了非密封类的解决方法。
1 - 继承外部类。
class MyWrapper : ExternalClass

2 - 为所有公共方法提取接口

class MyWrapper : ExternalClass, IExternalClass

3 - 取消外部类的继承。

class MyWrapper : IExternalClass

4 - 您将会获得一个有关类名的提示,提示该接口成员尚未被实现。按下Alt + Enter键,让Resharper自动实现它们。

5 - 使用此代码模板来包装属性。

    get { return $INNERCOMPONENT$.$NAME$; }
    set { $INNERCOMPONENT$.$NAME$ = value; }

6 - 使用此代码模板来包装方法

return $INNERCOMPONENT$.$NAME$($SIGNATURE$);

3

我不知道有哪种工具可以为您完成这个任务。

你可能已经知道,但 Visual Studio 只能提供接口的空实现,它只是走了一半的路。如果只是一次性任务,我会在这里停下来。

根据实际目标,使用其他方式可能会起作用,例如,对于测试,您可以使用模拟框架 - 通常有一种方法可以包装现有类并根据需要覆盖某些方法。


1
另一个非常简便的方法是使用Resharper为您生成“委托成员”,如此处所述:https://dev59.com/K3I95IYBdhLWcg3wyRM0#2150827 步骤:
  1. Create a new class that inherits from the class you want to wrap with a private variable of that class' type:

    public class ThirdPartyClassWrapper : ThirdPartyClass
    {
        private ThirdPartyClass _ThirdPartyClass;
    }
    
  2. Do a Alt-Insert in/on the class to use Resharper to generate "Delegating members". Choose the methods you want to expose and pass through to the private variable.

  3. If you have the free version of the GhostDoc extension installed you can highlight all of the created properties, methods, etc. and do a Ctrl-D to automatically grab all of the documentation from the base class and put it on the new members. (Resharper can do this too but I think you'd have to put "new" on each item which would then allow you to Alt-Enter and choose "Add xml-doc comments" from the Resharper popup menu).

  4. You can then delete the base class and do some additional cleanup in case the method/property signatures expose any other types that you need to wrap.


0
你所需要的是一个存根,可以通过创建自己的接口存根实现或使用Rhinomocks等模拟框架来完成。在测试目的下将困难的类包装在另一个类中对你没有任何好处。
此致 Morten

1
将一个复杂的类包装在另一个类中进行测试并没有什么好处。我认为这会减少耦合,并允许以后进行自定义实现。 - user295190
是的,但为什么不暂时为接口设置存根,并让它成为测试的输入呢?如果您使用实现,那么您也在测试它,这使得您的测试成为集成测试。 - Morten
没错,我不会针对ThirdPartyClassWrapper进行测试,而是会存根接口。但是,我无法存根静态类。撇开测试不谈,我认为这将在以后的道路上真正受益。 - user295190
如果输入类是静态的,您可以通过委托注入静态函数。因此,在测试时,可以用非静态/存根实现替换静态类中的方法使用。 - Morten

0

我强烈建议你去了解像Fakeiteasy这样的模拟框架。

但是为了给你提供你所要求的内容,请看下面。我怀疑当其他人回答时,ReSharper没有这个操作。

  1. 将接口添加到您希望成为包装类的类中

    class MyWebElement : IWebElement { }
    

  1. 找到/点击“将“YourInterfaceHere”的实现委托给新字段” Delegate Implementation

  1. 选择您的选项 委托选项

  • 点击“完成”并享受您的新课程

    class MyWebElement : IWebElement
    {
        private IWebElement _webElementImplementation;
        public IWebElement FindElement(By @by)
        {
            return _webElementImplementation.FindElement(@by);
        }
    
        public ReadOnlyCollection<IWebElement> FindElements(By @by)
        {
            return _webElementImplementation.FindElements(@by);
        }
    
        public void Clear()
        {
            _webElementImplementation.Clear();
        }
    
        public void SendKeys(string text)
        {
            _webElementImplementation.SendKeys(text);
        }
    
        public void Submit()
        {
            _webElementImplementation.Submit();
        }
    
        public void Click()
        {
            _webElementImplementation.Click();
        }
    
        public string GetAttribute(string attributeName)
        {
            return _webElementImplementation.GetAttribute(attributeName);
        }
    
        public string GetCssValue(string propertyName)
        {
            return _webElementImplementation.GetCssValue(propertyName);
        }
    
        public string TagName
        {
            get { return _webElementImplementation.TagName; }
        }
    
        public string Text
        {
            get { return _webElementImplementation.Text; }
        }
    
        public bool Enabled
        {
            get { return _webElementImplementation.Enabled; }
        }
    
        public bool Selected
        {
            get { return _webElementImplementation.Selected; }
        }
    
        public Point Location
        {
            get { return _webElementImplementation.Location; }
        }
    
        public Size Size
        {
            get { return _webElementImplementation.Size; }
        }
    
        public bool Displayed
        {
            get { return _webElementImplementation.Displayed; }
        }
    }
    

  • 网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接