将依赖于第三方 API 的 class 的部分分离到单独的程序集中

Separating parts of a class which depend on a 3rd party API into a separate assembly

我正在开发一个处理来自第 3 方 .NET 的对象的应用程序 API。处理器是通过实现以下 IProcessor 接口创建的。

public interface IProcessor
{
    Process(ApiClass input);
}

此接口的具体实现还可以添加其他属性来控制特定处理器的工作方式。例如...

public class ProcessorA : IProcessor
{
    public double X;
    public double Y;

    public Process(ApiClass input)
    {
       //Code here...
    }
}

public class ProcessorB : IProcessor
{
    public string MyParameter;
    public string MyOtherParameter;

    public Process(ApiClass input)
    {
       //Code here...
    }
}

第三方 API 和 ApiClass 只能在本机应用程序内部运行。但是,我希望能够创建其他能够读写处理器但不需要引用第 3 方 API 的 .NET 程序集。具体来说,我希望能够 serialize/deserialize 处理器 to/from JSON.

因此,我正在尝试确定将处理器的参数及其 IProcessor.Process() 的实现拆分为两个单独的程序集的最佳方法。一个引用了第 3 方 API,另一个没有。

一种选择是制作对象的重复代理版本。

//In assembly that does NOT reference 3rd party API
public class ProcessorAProxy
{
    public double X;
    public double Y;
}

//In assembly that references 3rd party API
public class ProcessorA 
{
    public double X;
    public double Y;

    public Process(ApiClass input)
    {
       //Code here...
    }
}

但这需要我在这些 class 之间保持属性同步。我还必须编写映射代码来在它们之间进行转换。

另一种选择是将参数存储在代理 class 中,然后创建一个继承自 class 的 class,它添加了 Process() 方法。

//In assembly that does NOT reference 3rd party API
public class ProcessorA
{
    public double X;
    public double Y;
}

//In assembly that references 3rd party API
public class ProcessorA : ProcessorAProxy
{
    public Process(ApiClass input)
    {
       //Code here...
    }
}

此选项不再具有我需要保持同步的重复属性。但是,如果我反序列化 ProcessorAProxy,我不确定如何将它转换为真正的 ProcessorA 而不必再次处理映射值。

除了继承 classes 之外,我还可以将选项注入到 class 中,它实际上通过其构造函数进行处理。

//In assembly that does NOT reference 3rd party API
public class ProcessorAOptions: IOptions 
{
    public double X;
    public double Y;
}

//In assembly that references 3rd party API
public class ProcessorA : IProcessor
{ 
   public ProcessorAOptions Options;

   public ProcessorA(ProcessorAOptions opt)
   {
       Options = opt;
   }

    public Process(ApiClass input)
    {
       //Code here...
    }
}

然后我将反序列化 IOptions 的特定类型,然后需要将其传递给 IProcessor 的正确具体类型的构造函数。这可以通过 ProcessorFactory.

来处理
IOptions options = serializer.Read(); //Read the some options
ProcessorFactory fact = new ProcessorFactory(); //Create a factory
IProcessor proc = fact.GetProcessor(options); //Get the processor for options from the factory

到目前为止,我最喜欢这个选项,但我不确定 ProcessorFactory 从特定类型的 IOptions 映射到正确的 IProcessor 的最佳方式类型。

一个选项是创建一个巨大的 if 语句来检查每个选项,类型。

if(opt.GetType() == typeof(ProcessorAOptions))
{
    return new ProcessorA((ProcessorAOptions)opt);
}
else if(opt.GetType() == typeof(ProcessorBOptions))
{
    return new ProcessorB((ProcessorBOptions)opt);
}
etc.. etc..

这可行,但似乎有点低效,尤其是当我有很多处理器类型时。

另一种选择是使用约定和反射。例如,找到一个实现 IProcessor 的 class,并具有一个将特定 IOptions 类型作为参数的构造函数。或者找到一个 class,其名称等于选项 class 的名称,删除 "Options" 后缀(ProcessorBOptions -> ProcessorB)。

使用反射有更好的选择吗?总的来说,有没有更好的方法将引用第三方 API 的代码和不引用第三方的代码拆分为 classes 在不同的程序集中,这些程序集如何相互映射?

您的最后一个方法类似于 WebRequest 在 CLR 中的工作方式。您将 Uri 传递给 Create,它 return 是要使用的正确子类。

https://msdn.microsoft.com/en-us/library/system.net.webrequest(v=vs.110).aspx

如果您查看 WebRequest.Create 的参考来源,您可以 运行 通过 Microsoft 使用的一些模式:

http://referencesource.microsoft.com/#System/net/System/Net/WebRequest.cs,117

http://referencesource.microsoft.com/#System/net/System/Net/Internal.cs,1608

一般来说,它归结为从内部查找中选择类型的名称并使用 Activator.CreateInstance 到 return 正确的派生类型。

https://msdn.microsoft.com/en-us/library/system.activator.createinstance(v=vs.110).aspx