我知道如何在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);
}
...
}
重申 - 我有一大堆代码,我不想改变,所以保持调用签名相同很重要 - 这个解决方案实现了这个
答案 0 :(得分:5)
你不能,这是.NET和大多数面向对象系统/语言中类型系统的限制。
原因是“可插入的东西”(正如你所指的那样)需要polymorphism才能生效。
您定义合同(以.NET语言表示的接口),然后实施该合同。您的系统只与签订合同。
静态成员在.NET中不是多态的,因此您永远无法让它们实现合同。
对于您的磁盘I / O抽象示例,您不会为此创建静态类,您可以创建一个接口,并实现接口,传递接口。
当然,使用界面的好处是可以更轻松地测试合同执行的双方:
对于磁盘I / O抽象,对于调用合同的所有内容,您永远不必担心实际触摸文件系统,您只需要使合同行为(通过适当的模拟设置)就像 触摸文件系统一样。
如果您有通过静态成员公开的现有服务,并且您希望能够将其与其他实现交换,那么您将必须执行以下操作:
答案 1 :(得分:1)
静态类不是“可插拔的”。如果您希望能够将其交换掉,则需要重构它以使用可以注入的接口。
某些类具有静态Current
或Default
参数,例如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)
让你在宿主应用程序中驻留静态类并且实际上是一个工厂:通过接口返回插件提供的实现。