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