如何最好地封装第三方类 C#?

7

我开始使用依赖注入,但是很难处理一些第三方库类。例如,我的项目中有EPPlus库,其中有ExcelRange类,它没有实现接口。由于我正在使用该库,我发现我的代码明显依赖于它,并且无法正确地对某些代码部分进行单元测试。

因此,我的问题是如何有效地在第三方库类中使用依赖注入。


有一些书讨论了解决问题的方法,比如GoF(即设计模式)和《与遗留代码有效地工作》。这两本书都是非常好的阅读材料,通常也很有用,除了广泛涵盖你的问题之外。 - Alexei Levenkov
1个回答

9
我的建议是创建另一个类和接口来包装你的第三方库。在你的包装器中,创建与你在第三方库中使用的同名函数。只创建那些对你的代码有价值的函数,如果需要其他函数,请逐步将其添加到你的包装器中。现在,为了测试目的,你可以模拟/存根你的包装器接口,而不使用你的第三方库。使用你的包装器将其注入到需要此服务的其他类中。
你可以从简单的代码开始,并随着你的知识增长扩展它:
public interface IWrapperService
{
    Method(Dto model);

    Dto MethodProcess(Dto model);
}

public class WrapperService : IWrapperService
{
    private readonly ThirdPartyLib _thirdPartyLib;

    public WrapperService(ThirdPartyLib thirdPartyLib)
    {
        _thirdPartyLib = thirdPartyLib;
    }

    // Create your model - Dto
    // Dto will help you in your logic process
    // 
    public void Method(Dto model)
    {   
        //extract some properties in you model that only needed in your third party library 
        _thirdPartyLib.Method(parameter needed);
    }

    public Dto MethodProcess(Dto model)
    {   
        //extract some properties in you model that only needed in your third party library 
        ThirdPartyReturn value = _thirdPartyLib.MethodProcess(parameter needed);

        // Do the mapping
        var model = new Dto 
        {
            property1 = value.property1 // Do the necessary convertion if needed.
            .
            .
        }

        return model;
    }
    .
    .
    .
}

public interface IOtherClass 
{
  ...
}

public class OtherClass : IOtherClass 
{
   private readonly IWrapperService _wrapperService;

   public void OtherClass(IWrapperService wrapperService)
   {
        _wrapperService= wrapperService;
   }
   .
   .
}

对于依赖注入,您可以使用Microsoft Unity。它将为您的依赖项执行出色的工作。您可以像这样使用它:

var unity = new UnityContainer();

// This is how you will inject your ThirdPartyLib
// You can also do it this way - unity.RegisterType<ThirdPartyLib>() but of course we need to limit the usage of your ThirdPartyLib in 
// our wrapper. We will not allowing directly access to Third Party Lib rather than wrapperService.

unity.RegisterType<IWrapperService, WrapperService>(new InjectionConstructor(new ThirdPartyLib()));
unity.RegisterType<IOtherClass, OtherClass>();

我同意 @Alexei Levenkov 的观点,你需要阅读一些Gang of Four (GOF)的相关内容来改进这个示例。把我的示例作为你的起点。

将第三方库包装起来可以带来以下优点:

  • 它消除了零散和直接使用第三方库的情况。
  • 封装了第三方库中的一些复杂性。
  • 通过包装器轻松跟踪和维护您的第三方库。
  • 现在可以通过使用包装器进行单元测试。
  • 依赖注入将有助于跨越关注点。

少量缺点:

  • 繁琐,并且会引入方法的重复。
  • 引入新模型-这取决于您的第三方库是否只需要像(int, string, boolean)这样的参数,如果不需要则无需创建新模型。
  • 一开始可能很难应用设计模式,但从长远来看会给你带来好处。

谢谢您的回复。这是一个相当大的库需要一对一地进行封装。如果没有其他办法,我想我必须花时间来做这件事。您能提供一个例子吗? - Farukh

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