类型参数约束似乎不适用于返回的类型

Rob*_*n B 5 c# generics constraints

我目前正致力于实现惰性定位自托管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];
      }
  }
Run Code Online (Sandbox Code Playgroud)

该类型Client.WCFClient<WCFCommunication.IWCFServiceBase>无法隐式转换为Client.WCFClient<T>.

显然,T != IWCFServiceBase除非您考虑类型约束,否则就是这种情况where T : IWCFServiceBase.

所以,为什么C#不这样做,我出错了什么?我觉得在尝试使用泛型时一定有一个很大的错误.

Jon*_*eet 2

内部字典只“知道”它有 aWCFCLient<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...
}
Run Code Online (Sandbox Code Playgroud)

或者为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...
}
Run Code Online (Sandbox Code Playgroud)