c# - 获取 .net core 中的开放通用类型列表
问题描述
尝试根据名称动态解析特定的实现(除非有更好的方法)
有客户:
public interface IClient { }
public interface IClient<TModel> : IClient where TModel : ListingBase // ListingBase is abstract class
{
public Task<TModel> MapToObject(Stream file);
}
// base class with common funcationality
public abstract class ClientBase<TModel> : IClient<TModel> where TModel : ListingBase
{
protected ClientBase(IHttpClient httpClient)
{
HttpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
}
public IHttpClient HttpClient { get; }
public abstract Task<TModel> MapToObject(Stream file);
... // other stuff
}
实现:
public class Client1 : ClientBase<Model1> // Model1 inherits from ListingBase
{
{
public override Task<Model1> MapToObject(Stream file) // Model1 inherits from ListingBase
{
// do mapping from Json / Stream to object
return Task.FromResult(new Model1());
}
}
// Another client
public class Client2 : ClientBase<Model2> // Model2 inherits from ListingBase
{
{
public override Task<Model2> MapToObject(Stream file) // Model2 inherits from ListingBase
{
// do mapping from Json / Stream to object
return Task.FromResult(new Model2());
}
}
然后在某个服务的某个地方注入 ClientFactory,我需要根据配置中指定的“名称”获取正确的客户端:
public interface IClientFactory
{
IClient<ListingBase> GetClient(string clientName);
}
public class ClientFactory : IClientFactory
{
private readonly IServiceProvider _serviceProvider;
public ClientFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
}
public IClient<ListingBase> GetClient(string clientName)
{
var clients = _serviceProvider.GetServices(typeof(IClient)); // this works - I get a list of 2
// match by name
var client = clients.FirstOrDefault(); // TODO - but for now get first
return (IClient<ListingBase>) client; // failing here - invalid cast
}
}
错误:
无法将“Client1”类型的对象转换为“Abstract.IClient”1..
在某些服务中,希望根据字符串获取特定客户端:
public class DefaultProcessor
{
private readonly IListingRepository _repository;
public DefaultProcessor(
IClientFactory clientFactory,
...
Client = clientFactory.GetClient("name-from-config");
}
public async Task Write(Stream file, CancellationToken cancellationToken = default)
{
var model = await Client.MapToObject(file);
...
}
}
解决方案
要将SaborClient
(我想实现IClient<?>
)转换为IClient<ListingBase>
您需要IClient<T>
是协变的T
,但为此您也需要Task<T>
是协变的T
。事实并非如此,因为 Task<>
类和方差声明仅在接口上可用。
您可以使用构造良好的界面绕过此限制,请参阅此答案。
这里是一个实现示例(您需要导入MorseCode.ITask NuGet 包):
public abstract class ListingBase
{
}
public class Model1 : ListingBase
{
}
public interface IClient
{
}
// Note the *out* here
public interface IClient<out TModel> : IClient where TModel : ListingBase
{
public ITask<TModel> MapToObject(Stream file);
}
public class Client1 : IClient<Model1>
{
public async ITask<Model1> MapToObject(Stream file)
{
return new Model1();
}
}
public class ClientFactory
{
public IClient<ListingBase> GetClient()
{
var client = GetClientInternal();
return (IClient<ListingBase>) client;
}
private static IClient GetClientInternal() => new Client1();
}
class Program
{
static void Main(string[] args)
{
var factory = new ClientFactory();
var client = factory.GetClient();
Console.WriteLine("Client:" + client);
Console.ReadLine();
}
}
推荐阅读
- woocommerce - WooCommerce 产品变化自定义字段及其价格计算
- r - 在 R tidyverse 中删除重复项时保留最后一次观察
- sql-server - 如何从两个不同的表中选择数据并计算行数
- python - PolynomialFeatures 和 LinearRegression 返回不需要的系数
- jquery - DataTables 警告:表 id=TableID - 无效的 JSON 响应
- javascript - 试图加快我的脚本比较 2 个数组(不是 for 循环)
- php - ErrorException 复制(C:\laragon\www\himochibear\database/seeders/IndoRegionDistrictSeeder.php):无法打开流:没有这样的文件目录
- python - 蒙特卡洛模拟(计算某个结果的概率)(Jupyter-notebook)
- javascript - 动画传单标记落后
- assembly - 如何培养对 LC-3 汇编代码的直觉?