Цикл через интерфейсы объекта - PullRequest
0 голосов
/ 26 октября 2018

Я создаю универсальный локатор служб, но у меня проблема.У меня есть способ добавить или заменить услугу.Служба должна быть заменена, если в текущем списке услуг есть только 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

Дело в том, что если в списке есть и 1011 *, и 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));

Помощь будет принята с благодарностью!Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 26 октября 2018

Использование словаря с типом интерфейса в качестве ключа было бы намного проще и эффективнее, поскольку не потребовалось бы зацикливания.

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] Свойство

0 голосов
/ 26 октября 2018

Ну, ваша логика ошибочна. Вот что происходит:

  1. 2 первых вызова в UT для AddOrReplaceService () добавляют 2 сервиса в набор сервисов
  2. 3-й вызов в UT заменит класс TestB на копию TestAB, потому что TestA нельзя назначить из IB

Никогда не было бы ситуации, когда число найденных сервисов было бы больше, чем 1. Таким образом, чтобы увидеть, что исключение выдается, вам нужно удалить второе условие из переключателя внутри AddOrReplaceService (). И вам не следует проверять реализацию каких-либо интерфейсов, кроме тех, которые вы пытаетесь добавить в свою коллекцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...