我正在开发一个基于 .NET 的应用程序,其中一些核心应用程序类仅使用静态 方法设计。
示例用法:
// static access.
Parameters.GetValue("DefaultTimeout");
// static access.
Logger.Log("This is an important message!");
已经有使用这些静态方法的代码,因此无法更改此“接口(interface)”。
这些类目前没有实现接口(interface)。我希望能够将这些类的实际实现与其接口(interface)分开。
进行此重构的原因是这些对象将跨 AppDomain 边界使用。我希望能够注入(inject)一个“代理”对象,在非主应用程序域上将调用其他实现而不是默认实现。
总而言之,我的问题是:
我如何轻松地将仅具有静态访问权限的对象转换为基于接口(interface)的设计,以便在需要时可以替换它们的实现(但保持静态访问)。
重构后,非默认实现的实际注入(inject)应该如何/何时发生?
最佳答案
免责声明:以下建议是基于不改变调用方的重要性。我并不是说这是最好的选择,只是我认为它是合适的。
断开实现
没有办法在静态成员上拥有接口(interface),因此如果您不想更改调用代码,静态成员可能必须保留。也就是说,您可以简单地在静态类中包装一个接口(interface),因此静态类本身没有任何实现 - 它将所有调用委托(delegate)给接口(interface)。
这一切意味着您可以保留静态类和调用它的任何代码。这就像将静态类视为接口(interface)(或契约),但让它根据情况在内部交换实现。
这也意味着您的接口(interface)可以具有与静态类不同的签名,因为接口(interface)不必符合调用代码的预期 - 基本上,它会将您的静态类变成一种 Bridge .
注入(inject)实现
简而言之:使用静态构造函数来解析此接口(interface)的给定实现。
静态通常是每个 AppDomain(除非用 ThreadStaticAttribute
修饰,然后是每个 AppDomain/thread)所以你可以根据当前的 AppDomain 确定你在哪里以及你需要什么实现(静态构造函数将是每当在 AppDomain 中首次使用静态时调用)。这意味着一旦构建,该特定静态类的包装实现将在 AppDomain 的持续时间内保留(尽管您可以实现刷新实现的方法)。
跨应用域调用
负责此的代码可以在静态类中,也可以使接口(interface)实现之一简单地成为 AppDomain 类型的代理管理器。跨 AppDomain 调用的任何类型都需要继承 MarshalByRefObject
。
http://msdn.microsoft.com/en-us/library/ms173139.aspx
CreateInstance of a Type in another AppDomain
Simplest way to make cross-appdomain call?
示例应用程序
您应该能够将其复制并粘贴到新的控制台应用程序中。这是在为默认的 AppDomain 和用户创建的 AppDomains 注册一个实现。默认只是创建接口(interface)的远程实现(在另一个 AppDomain 中)。只是为了演示“每个 AppDomain 静态”的想法,远程实现委托(delegate)给非默认域的另一个实现。
您可以即时更改实现,您需要更改的只是静态类构造函数(决定选择什么实现)。请注意,您无需更改 Main
方法,即本例中的调用代码。
using System;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine(Parameters.GetValue(""));
Console.Read();
}
}
static class Parameters
{
private static IParameterProvider _provider;
static Parameters()
{
if (AppDomain.CurrentDomain.IsDefaultAppDomain())
{
_provider = new ParameterProviderProxy(AppDomain.CreateDomain(Guid.NewGuid().ToString()));
}
else
{
// Breakpoint here to see the non-default AppDomain pick an implementation.
_provider = new NonDefaultParameterProvider();
}
}
public static object GetValue(string name)
{
return _provider.GetValue(name);
}
}
interface IParameterProvider
{
object GetValue(string name);
}
class CrossDomainParameterProvider : MarshalByRefObject, IParameterProvider
{
public object GetValue(string name)
{
return Parameters.GetValue(name);
}
}
class NonDefaultParameterProvider : IParameterProvider
{
public object GetValue(string name)
{
return AppDomain.CurrentDomain.FriendlyName;
}
}
class ParameterProviderProxy : IParameterProvider
{
private IParameterProvider _remoteProvider;
public ParameterProviderProxy(AppDomain containingDomain)
{
_remoteProvider = (CrossDomainParameterProvider)containingDomain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName,
typeof(CrossDomainParameterProvider).FullName);
}
public object GetValue(string name)
{
return _remoteProvider.GetValue(name);
}
}
关于生命周期的注释
管理静态类重构的主要问题之一通常不是更改客户端代码(因为许多重构工具都支持这一点,并且有一些技术可以安全地完成它),而是管理生命对象的跨度。实例对象依赖于事件引用(否则它们会被垃圾收集),通常可以通过将一个对象保存在某个公共(public)静态成员中来使它们“易于访问”,但通常这是您首先要通过重构来避免的。
您似乎不必担心这个问题,因为您将调用代码附加到静态类,因此生命周期将保持不变。
关于c# - 重构静态类以将其接口(interface)与实现分离,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10775534/