我正在创建一个通用服务定位器,但遇到了问题。 我有一种添加或替换服务的方法。如果当前服务列表中只有 1 个候选者,则必须更换该服务。
// IA - TestA
// IB - TestB
// IA/IB - TestAB
// <IB> TestAB
public static void AddOrReplaceService<T>(T serviceToAdd) where T: class
{
if (serviceToAdd == null)
throw new ArgumentNullException(nameof(serviceToAdd));
List<T> foundServices = new List<T>();
int index = -1;
for (int i = 0; i < _services.Count; i++)
{
if (!(_services[i] is T)
&& !_services[i].GetType().IsAssignableFrom(typeof(T))
&& !_services[i].GetType().IsInstanceOfType(serviceToAdd)
&& !serviceToAdd.GetType().IsInstanceOfType(_services[i]))
continue;
foundServices.Add((T) _services[i]);
if (index == -1)
index = i;
}
switch (foundServices.Count)
{
case 0:
AddService(serviceToAdd);
break;
case 1:
_services[index] = serviceToAdd;
return;
default:
throw new MultipleServicesAlreadyExistsException("Multiple services found with " + typeof(T).Name
+ foundServices.ToStringCollection(", "));
}
}
为了测试我的服务定位器,我有 2 个接口
IA
和 IB
和 3 个类,TestA : IA
、TestB : IB
和 TestAB : IA, IB
问题是,如果
TestA
和 TestB
都在列表中,并且您尝试添加 TestAB
,它应该给出例外,因为 TestA
和 TestB
都在实现 TestAB
的接口。
我尝试添加一堆
AssignableFrom
等逻辑。但是,我无法让它工作。
这是单元测试的一部分
[Test]
public void Test()
{
try
{
ServiceLocator.Reset();
Assert.IsTrue(AddService<IA>(new TestA(), false));
Assert.IsTrue(AddService<IB>(new TestB(), false));
// TestAB implements IA and IB so replacing should fail;
Assert.IsTrue(AddOrReplaceService<IB>(new TestAB(), true));
非常感谢您的帮助!预先感谢。
使用以接口类型为键的字典会更容易且性能更高,因为不需要循环。
private static readonly Dictionary<Type, object> _services = new Dictionary<Type, object>();
public static void AddOrReplaceService<T>(T serviceToAdd) where T: class
{
if (serviceToAdd == null)
throw new ArgumentNullException(nameof(serviceToAdd));
_services[typeof(T)] = serviceToAdd;
}
这会自动执行几件事:
由于您将参数
serviceToAdd
输入为 T
,C# 编译器确保服务类与接口 T
的分配兼容(无需测试)。此外,无需测试您要替换的服务是否是正确的类型,因为它是通过相同的方法添加的,只能使用正确类型的服务进行调用。
嗯,你的逻辑有问题。这是发生的事情:
永远不会出现
foundServices
的数量比 1 多的情况。
因此,为了看到抛出异常,您需要从AddOrReplaceService()
内的开关中删除第二个条件。除了您尝试添加到集合中的接口之外,您不应该检查任何接口的实现。