Ограничение параметра типа, похоже, не применяется к возвращаемому типу - PullRequest
0 голосов
/ 27 апреля 2018

В настоящее время я работаю над реализацией размещенных самостоятельно служб WCF. Эти сервисы определяют свои контракты в общем интерфейсе с клиентом и хостом, который должен наследоваться от IWCFServiceBase.

После того, как WCFHost хостит интерфейс, указанный параметром типа, ограниченным IWCFServiceBase: public class WCFHost<T> where T : WCFServiceBase, IWCFServiceBase, клиент может подписаться на этот хост, указав интерфейс и идентификатор сервиса: public class WCFClient<T> : IDisposable where T : IWCFServiceBase. Пока что этот функционал работает без нареканий.

Теперь я хотел попробовать отсортировать сервисы Lazy-Discover и сохранить доступный канал для каждой обнаруженной службы. Эта функциональность обеспечивается локатором, который содержит все обнаруженные сервисы в этой структуре: public Dictionary<string, Dictionary<IWCFServiceBase, WCFClient<IWCFServiceBase>>> Services;

Теперь, предполагая, что служба использовалась ранее, поэтому она уже обнаружена и сохранена в словаре. Я использую следующий код для ее получения:

 public WCFClient<T> GetMicroService<T>(string servicename, T contract) where T : IWCFServiceBase
 {
      if (this.Services.ContainsKey(servicename) && this.Services[servicename].ContainsKey(contract))
      {
          return this.Services[servicename][contract];
      }
  }

Тип Client.WCFClient<WCFCommunication.IWCFServiceBase> не может быть неявно преобразован в Client.WCFClient<T>.

Очевидно, что это случай T != IWCFServiceBase, за исключением случаев, когда принимается во внимание ограничение типа where T : IWCFServiceBase.

Так почему же C # не делает этого и что я не так понял? Я чувствую, что в том, как я пытаюсь использовать дженерики, должна быть большая ошибка.

1 Ответ

0 голосов
/ 27 апреля 2018

Внутренний словарь только «знает», что он имеет WCFCLient<IWCFServiceBase> в качестве значения. Вы ничего не можете добавить туда любой WCFCLient<IWCFServiceBase>. Возможно, вы гарантировали, что указали только правильные значения, но компилятор не может этого сказать. Вам просто нужно добавить актерский состав, чтобы показать, что вы уверены.

Я бы тоже использовал TryGetValue вместо ContainsKey. Предполагая, что вы можете использовать C # 7:

public WCFClient<T> GetMicroService<T>(string serviceName, T contract)
    where T : IWCFServiceBase
{
    if (Services.TryGetValue(serviceName, out var service) &&
        service.TryGetValue(contract, out var client))
    {
        // client will just be WCFClient<IWCFServiceBase>, so we need to cast
        return (WCFClient<T>) client;
    }
    // Throw an exception or whatever...
}

Или с отдельными объявлениями переменных для параметров out:

public WCFClient<T> GetMicroService<T>(string serviceName, T contract)
    where T : IWCFServiceBase
{
    Dictionary<IWCFServiceBase, WCFClient<IWCFServiceBase>> service;
    WCFClient<IWCFServiceBase> client;
    if (Services.TryGetValue(serviceName, out service) &&
        service.TryGetValue(contract, out client))
    {
        // client will just be WCFClient<IWCFServiceBase>, so we need to cast
        return (WCFClient<T>) (object) client;
    }
    // Throw an exception or whatever...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...