如何制作可插入的静态类

pm1*_*100 3 .net c# plugins static-classes

我知道如何在c#中制作可插拔的东西.定义一个接口,Activator.CreateInstance(<class>)等等.或者我可以有一个显式创建插件类实例的代码路径.很多种方法.

但是,如果我想要插件的服务是静态的(我知道我可以重构,所以它不是,但这不是问题的重点)

具体例子.我有一个提供磁盘I/O抽象的类(读取文件,列表目录,....).现在我想要这种抽象的不同实现,它可以提供来自真实FS,数据库的文件.

根据Olivier Jacot-Descombes的回复,我会有一个FileSystem类(这是真的)这样的

public static class FileSystem
{
    static IFSImplemenation s_imple;
    static FileSystem()
    {
        if(<some system setting>)
            // converted to singleton instead of static
            s_imple = new OldFileSystem() 
        else
            s_imple = new DbFileSystem();
    }

    public static byte[] ReadFile(string path)
    {
        return s_imple.ReadFile(path);
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

重申 - 我有一大堆代码,我不想改变,所以保持调用签名相同很重要 - 这个解决方案实现了

cas*_*One 5

你不能,这是.NET中类型系统和大多数面向对象系统/语言的限制.

原因是"可插入的东西"(正如你所指的那样)需要多态才能有效.

您定义一个合同(一个接口,在.NET中说),然后您实现该合同.您的系统只处理合同.

静态成员在.NET中不是多态的,因此您永远无法让它们实现合同.

对于您的磁盘I/O抽象示例,您不会为此创建静态类,您将创建一个接口,并实现接口,传递接口.

当然,使用界面的好处是可以更轻松地测试合同执行的双方:

  • 如果合同是客户端,您可以轻松地模拟界面并将模拟传递给合同的消费者(这是您可能开始考虑依赖注入的地方)
  • 您可以与系统的其余部分分开测试实施.

在磁盘I/O抽象的情况下,对于调用合同的所有内容,您永远不必担心实际触摸文件系统,您只需要使合同行为(通过适当的模拟设置)就像触摸它一样文件系统.

如果您有通过静态成员公开的现有服务,并且您希望能够将其与另一个实现交换,那么您将必须执行以下操作:

  • 创建一个抽象(契约/抽象类型),定义服务上的操作.
  • 创建一个实现,将调用从抽象实现的实例转发到静态方法.
  • 使用实现的实例重新连接到服务的所有静态调用.此时,你真的必须使用某种依赖注入; 如果你不这样做,你只是在呼叫站点创建具体实现,这几乎是相同的(如果你想使用另一个实现,你必须再次更改每个呼叫站点).