获取.net核心中的开放泛型类型列表



尝试根据名称动态解析特定实现(除非有更好的方法(

拥有客户:

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"的对象强制转换为类型'抽象.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();
}
}

最新更新