gpt4 book ai didi

c# - 重构静态类以将其接口(interface)与实现分离

转载 作者:太空狗 更新时间:2023-10-29 18:11:04 24 4
gpt4 key购买 nike

我正在开发一个基于 .NET 的应用程序,其中一些核心应用程序类仅使用静态 方法设计。

示例用法:

// static access.
Parameters.GetValue("DefaultTimeout");

// static access.
Logger.Log("This is an important message!");

已经有使用这些静态方法的代码,因此无法更改此“接口(interface)”。

这些类目前没有实现接口(interface)。我希望能够将这些类的实际实现与其接口(interface)分开。

进行此重构的原因是这些对象将跨 AppDomain 边界使用。我希望能够注入(inject)一个“代理”对象,在非主应用程序域上将调用其他实现而不是默认实现。

总而言之,我的问题是:

  1. 我如何轻松地将仅具有静态访问权限的对象转换为基于接口(interface)的设计,以便在需要时可以替换它们的实现(但保持静态访问)。

  2. 重构后,非默认实现的实际注入(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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com