遍历对象的接口

时间:2018-10-26 14:46:52

标签: c# generics design-patterns reflection

我正在创建通用服务定位器,但是有问题。 我有一种添加或替换服务的方法。如果当前服务列表中只有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个接口IAIB以及3个类,TestA : IATestB : IBTestAB : IA, IB

问题是,如果TestATestB都在列表中,而您尝试添加TestAB则应该给出一个例外,因为TestA和{{1} }正在实现TestB的接口。

我尝试添加一堆TestAB等逻辑。但是,我无法正常工作。

这是单元测试的一部分

AssignableFrom

我们将不胜感激!预先感谢。

2 个答案:

答案 0 :(得分:0)

嗯,您的逻辑有缺陷。这是正在发生的事情:

  1. 在UT中2个首次调用AddOrReplaceService()将2个服务添加到服务集合中
  2. UT中的第3次调用将用TestAB的副本替换TestB类,因为不能从IB分配TestA。

永远不会有一个情况,那就是FoundServices的数量会更多,然后是1。 因此,为了查看抛出异常,您需要从AddOrReplaceService()内部的开关中删除第二条件。而且,除了要添加到集合中的接口之外,您都不应该检查任何接口的实现。

答案 1 :(得分:0)

使用具有接口类型作为键的字典会容易得多,并且由于不需要循环,因此执行起来会更容易。

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;
}

这会自动执行以下操作:

  1. 它确保每个接口仅注册一项服务。
  2. 如果尚未注册界面,它将自动添加服务。
  3. 它会自动替换同一接口的现有服务。

由于您将参数serviceToAdd键入为T,因此C#编译器确保服务类的分配与接口T兼容(无需测试)。另外,无需测试您要替换的服务是否属于正确的类型,因为它是通过相同的方法添加的,只能使用正确的类型的服务来调用。

请参阅:Dictionary.Item[TKey] Property