【问题标题】:How to resolve a "No implicit reference conversion" issue when using Generics & Interfaces使用泛型和接口时如何解决“无隐式引用转换”问题
【发布时间】:2020-10-25 11:51:59
【问题描述】:

任何想法我可以如何修复以下错误或重构我的方法以避免它?

我定义了以下接口:

public interface IApiClient<TConfig, TOrder>
    where TConfig : IApiClientConfiguration
    where TOrder : IApiClientOrder
{
    TConfig Configuration { get; }

    IApiClientOrderConverter<TOrder> GetOrderConverter();

    Task<IEnumerable<TOrder>> GetNewOrdersAsync();
}

public interface IApiClientOrderConverter<TOrder>
    where TOrder : IApiClientOrder
{
    WarehouseOrder ClientOrderToWarehouseOrder(TOrder order);
}

基于它的实现:

public class SolidApiClient : IApiClient<SolidApiClientConfiguration, SolidOrder>
{
    public SolidApiClientConfiguration Configuration { get; }
    
    public IApiClientOrderConverter<SolidOrder> GetOrderConverter()
    {
        ...
    }
    
    public async Task<IEnumerable<SolidOrder>> GetNewOrdersAsync()
    {
        ...
    }
}

我正在尝试使用以下签名调用一个函数:

protected async Task ProcessClients<T>(IEnumerable<IApiClientConfiguration> clientConfigs)
    where T : IApiClient<IApiClientConfiguration, IApiClientOrder>
{
    ...
}

我试图这样称呼它:

await ProcessClients<SolidApiClient>(clientsConfig);

但由于以下错误,我无法使用 SolidApiClient 进行通用调用:

错误 CS0311 类型“SolidApiClient”不能用作泛型类型或方法“Function.ProcessClients(string, IEnumerable)”中的类型参数“T”。没有从“SolidApiClient”到“IApiClient”的隐式引用转换。

我在这里看到了许多类似的不同问题,但我还没有设法从迄今为止找到的答案中找到解决方案,所以我伸出手,以防有人发现我的方法有什么问题错过了。

我也尝试了我的方法的一些变体,但似乎只是将问题转移到代码的不同部分,所以相信我必须对接口类和泛型使用有缺陷的方法。

【问题讨论】:

  • IApiClient 至少可以声明为IApiClient&lt;out TConfig, TOrder&gt;。 可能它可以被声明为IApiClient&lt;out TConfig, out TOrder&gt;,但没有看到IApiClientOrderConverter&lt;&gt;是如何被声明的,它是不可能的(如果它还没有,该接口也可以被声明为协变的)
  • 因此您可以将IApiClientOrderConverter 声明为逆变IApiClientOrderConverter&lt;in TOrder&gt; 不幸的是,这意味着IApiClient 在TOrder 中是不变量,因为它既是输入又是输出。换句话说,IApiClient&lt;out TConfig, in TOrder&gt; 和 IApClient&lt;out TConfig, out TOrder&gt; 均无效。这使您的界面为IApiClient&lt;out TConfig, TOrder&gt;,不幸的是这对您的问题没有帮助
  • @pinkfloydx33 感谢您的见解,非常感谢。我可以探索采取另一种方法的任何粗略想法吗?我有一些 Azure 函数,它们做的事情基本相同,从不同的 API 客户端导入订单,逻辑基本相同。客户端在实现上有所不同,但流程的样板代码是相同的,所以我试图找出最好的方法来提出一个好的 DRY 解决方案。
  • 您可以定义一些非泛型基接口(即使用object 或IApiClientOrder 作为返回/输入类型),然后在您的类中显式实现它们委托给通用版本。然后,您将使用非通用接口,然后可以在没有大量样板的情况下使用这些接口

标签: c# generics interface


【解决方案1】:

按照@pinkfloydx33 的建议,我改变了使用抽象基类的方法。

作为奖励,摆脱接口和泛型极大地简化了解决方案。在我的特定场景中,使用接口和泛型是一个糟糕的选择。

【讨论】:

    【解决方案2】:

    要使用ProcessClients,它需要定义与IApiClient&lt;...&gt; 相同的通用约束;

    ProcessClients<TClient, TConfig, TOrder>
        (IEnumerable<TConfig> clientConfigs)
        where TClient : IApiClient<TConfig, TOrder>
        where TConfig : IApiClientConfiguration
        where TOrder : IApiClientOrder
    

    这感觉就像是代码的味道。隐藏这种复杂性的另一种方法是定义更多的接口,这样您就不需要一直引用通用接口;

        interface IApiClient {}
        interface IApiClient<T> : IApiClient {}
    

    【讨论】:

    • 感谢您的建议。就我而言,我认为抽象基类使解决方案更简单,更易于维护。他们也开始积累共享逻辑,现在第二个 APiClient 已添加到组合中,因此感觉它正在朝着更好的方向发展。
    猜你喜欢
    • 1970-01-01
    • 2021-12-10
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多