我正在开发一个服务定位器系统,服务可以在代码库周围注册并得到请求。
如果您有兴趣,可以查看整个代码。
我遇到的问题,我正在尝试使它,以便如果服务实例已经注册,注册失败,我这样做:
/// <summary>
/// Registers a service.
/// More than one instance of a service type is allowed.
/// Registration will fail if the same instance has already registered itself.
/// </summary>
public static void Register(IService service)
{
Type type = service.GetType();
List<IService> list = GetServiceList(type, out list);
if (list.IsEmpty())
dic[type] = list;
else if (list.Contains(service))
throw new RegistrationException("[Vervices]: Service instance: `" + service + "` has already registered!");
else if (list.FirstOrDefault(s => s.Identifier == service.Identifier) != null)
throw new RegistrationException("[Vervices]: There already exist a service instance of id: `" + service.Identifier);
list.Add(service);
if (service is MonoBehaviour)
Object.DontDestroyOnLoad(service as MonoBehaviour);
}
与其做一个list.Contains(service)
我想为什么不让每个服务都有一个HasRegistered
- 当我注册一个服务时,我将其设置为 true。现在界面将如下所示:
public interface IService
{
void Ping(Object sender);
string Identifier { get; }
bool HasRegistered { get; set; }
}
现在我可以只做if (service.HasRegistered) throw exception;
而不是if (list.Contains(service) throw exception;
但问题是,这并不安全。该物业既有公共二传手,也有吸引人,这意味着任何外人都可以进来做service.HasRegistered = false;
!!!
它应该设置为 true,仅在 Register
内部 - 我该怎么做? - 如果我将二传手设为私有,我无法在任何地方设置它,如果我在同一个问题IService
内部进行NotifyHasBeenRegistered()
,外人可能会调用它并引起问题。
我怎样才能以安全的方式做我想做的事?
感谢您的帮助。
就个人而言,我会坚持Contains
方法,原因有两个:
- 定位器应负责了解已注册的服务,而不是服务(单一责任原则)。
- 使服务无法设置属性的唯一方法是对只有定位器可以设置的
internal
属性使用继承。同样,强制服务继承基类是非常严格的(因为 c# 不支持多重继承)。
如果您担心Contains
性能,则可以使用性能优于List<T>
的数据结构。"跳过列表"是一种具有类似于二叉搜索树的属性的列表。它允许您在 O(log n) 时间内搜索特定项目,而List<T>
需要 O(n) 时间(即慢得多)。
NGenerics 提供了 Skip 列表和其他几种有用的数据结构的实现: https://github.com/ngenerics/ngenerics
以下是数据结构性能的备忘单: http://bigocheatsheet.com/#data-structures