这是一个简短的片段,我已经隐藏了无关紧要的细节。目标是使我的工厂使用我的泛型设计类型。在文章的结尾,我有两个观察结果。
接口
public interface IWorker<T> where T : IWorkload
{
T CraftWorkload(string plainWorkload);
Task DoWork(T workload);
}
IWorkload
public interface IWorkload
{
// some properties
}
基类
internal abstract class Worker<T> : IWorker<T> where T : IWorkload
{
public T CraftWorkload(string workAsJsonString)
{
return JsonConvert.DeserializeObject<T>(workAsJsonString, new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Error
});
}
public abstract Task DoWork(T workload);
}
另一个派生基类
internal abstract class RestWorker<T> : Worker<T> where T : IWorkload
{
// this is a worker that interact with http requests
}
混凝土工人
internal class WorkerA: RestWorker<WorkerA_Workload>
{
public override Task DoWork(WorkerA_Workload workload)
{
}
}
internal abstract class WorkerB: Worker<WorkerB_Workload>
{
public override Task DoWork(WorkerB_Workload workload)
{
}
}
WorkersFactory
MessageType
是用类型标识工作者的枚举
internal interface IWorkerFactory
{
IWorker<IWorkload> GetWorker(MessageType type);
}
internal class WorkerFactory : IWorkerFactory
{
public IWorker<IWorkload> GetWorker(MessageType type)
{
switch (type)
{
case MessageType.WorkerA:
return new WorkerA() as IWorker<IWorkload>;
case MessageType.WorkerB:
return new WorkerB() as IWorker<IWorkload>;
.
.
.
.
.
default:
throw new ArgumentException("The type must be a type that maps to an available worker");
}
}
}
两个观察:
IWorker<IWorkload>
就返回,则会感到困惑我的继承有意义吗?
您的IWorker<T>
接口表示一个既可以产生T
类型的对象,又可以[消耗类型T
的对象的工作程序(因为它同时使用T
作为方法的参数和方法的返回类型)。这意味着IWorker<IWorkload>
是能够产生IWorkload
类型的对象的对象,WorkerA
和WorkerB
可以做到,因为它们产生的WorkerA_Workload
和WorkerB_Workload
对象是IWorkload
对象。但这也意味着IWorker<IWorkload>
需要能够接受*任何IWorkload
并对其进行处理。 WorkerA
和WorkerB
都不能这样做。它们只能分别接受WorkerA_Workload
和WorkerB_Workload
输入,但是要实现IWorker<IWorkload>
的接口,它们将必须能够接受< [任何其他类型的工作负载。
IWorkload
,并且实际上他们不需要接受特定类型的工作负载,那么您需要调整代码以基本上删除受IWorkload约束的所有通用类型,而改为只需在所有这些地方使用非通用IWorkload
类型。 (您还需要使IWorker<T>
相对于T
协变。)如果您的工作人员不能实际上接受任何IWorkload
,并且需要特定类型的工作负载,那么您不能将所有工作人员都视为IWorker<IWorkload>
,则需要始终将他们视为IWorker<T>
,其中T是他们可以接受的实际特定工作负载类型。