如何制作可插入的静态类

时间:2012-10-12 18:30:21

标签: c# .net 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);
    }

    ...
}

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

4 个答案:

答案 0 :(得分:5)

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

原因是“可插入的东西”(正如你所指的那样)需要polymorphism才能生效。

您定义合同(以.NET语言表示的接口),然后实施该合同。您的系统只与签订合同

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

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

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

  • 如果合同是客户,您可以轻松地模拟界面并将模拟传递给合同的消费者(这是您可能开始考虑的问题dependency injection
  • 您可以与系统的其他部分分开测试实施。

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

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

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

答案 1 :(得分:1)

静态类不是“可插拔的”。如果您希望能够将其交换掉,则需要重构它以使用可以注入的接口。

某些类具有静态CurrentDefault参数,例如ServiceLocator。然后,您可以使用ServiceLocator.Current访问静态上下文中的当前IServiceLocator

您可以稍微进一步隐藏Current对象。虽然我不建议这样做,但它将无需重构所有代码。但是,此方法的维护要高得多,因为Foo未实现IFoo

假设您有一个静态类Foo

static class Foo
{
    public static string GetBar() { return "Bar"; }
}

您可以创建一个界面IFoo

interface IFoo
{
    string GetBar();
}

现在将您的班级Foo更改为以下

static class Foo 
{
    private static IFoo _foo;

    public static void SetFoo(IFoo foo) { _foo = foo; }

    public static string GetBar() { return _foo.GetBar(); }
}

答案 2 :(得分:1)

将静态类用作非静态实现的外观

public static class DB
{
    private static IDbInterface _implementation;

    public static void SetImplementation(IDbInterface implementation)
    {
        _implementation = implementation;
    }

    public static Customer GetCustomerByID(int custId)
    {
        return _implementation.GetCustomerByID(custId);
    }

    ...
}

答案 3 :(得分:0)

让你在宿主应用程序中驻留静态类并且实际上是一个工厂:通过接口返回插件提供的实现。