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

时间:2018-04-27 07:42:18

标签: c# generics constraints

我目前正致力于实现延迟定位自托管WCF服务。这些服务在客户端和主机的公共接口中定义合同,这些接口必须从IWCFServiceBase继承。

WCFHost托管由IWCFServiceBase约束的类型参数指定的接口:public class WCFHost<T> where T : WCFServiceBase, IWCFServiceBase后,客户端可以通过指定接口和服务标识符来订阅此主机:{{1 }}。到目前为止,这个功能完美无瑕。

现在我想尝试对“Lazy-Discover”服务进行排序,并为每个已发现的服务保持可用的通道。此功能由定位器提供,该定位器保存此结构中的所有已发现服务:public class WCFClient<T> : IDisposable where T : IWCFServiceBase

现在假设之前已经使用过服务,因此它已经被发现并保存在字典中,我使用以下代码来检索它:

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

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

1 个答案:

答案 0 :(得分:2)

内部字典只“知道”它有一个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...
}