我遇到了与仿制协方差/逆差异冲突有关的以下问题。
public interface IEmailTemplateInput
{
List<string> ToEmail { get; set; }
string Subject { get; set; }
string FromEmail { get; set; }
}
public interface IEmailCommunicationTemplate<in TInputData> where TInputData : IEmailTemplateInput
{
void ProcessTemplate(TInputData input);
Task ProcessTemplateAsync(TInputData input);
}
// Below is the implementation using above interfaces
public class RiskPeerReviewNotificationTemplate
: IEmailCommunicationTemplate<RiskPeerReviewNotificationTemplate.Input>
{
private readonly IEmailService _emailService;
private readonly ITemplateService _templateService;
public class Input : IEmailTemplateInput
{
public string TenantName { get; set; }
public string FirstName { get; set; }
public string CallToActionUrl { get; set; }
}
public RiskPeerReviewNotificationTemplate(IEmailService emailService, ITemplateService templateService)
{
_emailService = emailService;
_templateService = templateService;
}
protected override Task ProcessAsync(Input input)
{
//... Method implementation
}
}
现在我想注册IEmailCommunicationTemplate并基于输入参数(在本例中为EmailTemplateType), 想要生成不同的实现。
But I run into problems during Autofac registration
// Register email templates
iocBuilder.Register<IEmailCommunicationTemplate<IEmailTemplateInput>>((c, p) =>
{
var type = p.TypedAs<EmailTemplateType>();
switch (type)
{
case EmailTemplateType.NewUserNotificationTemplate:
return new NewUserNotificationTemplate(c.Resolve<IEmailService>(),
c.Resolve<ITemplateService>());
case EmailTemplateType.RiskPeerReviewNotificationTemplate:
return new RiskPeerReviewNotificationTemplate(c.Resolve<IEmailService>(),
c.Resolve<ITemplateService>());
default:
throw new ArgumentException("Invalid Email Template type");
}
})
.As<IEmailCommunicationTemplate<IEmailTemplateInput>>();
现在显然我不能这样做,因为有反方差。上述注册的实际问题是因为我有效地做了类似的事情 IEmailCommunicationTemplate test2 = new RiskPeerReviewNotificationTemplate(emailService,templateService); 这是不可能的......
我无法改变 IEmailCommunicationTemplate其中TInputData:IEmailTemplateInput 到 IEmailCommunicationTemplate其中TInputData:IEmailTemplateInput
because TInputData also comes as parameter in methods (contraVariance nature)...
在stackoverflow上提出的一个解决方案
Generics, Covariance/Contravariance, etc
that would resolve compilation issue :
1) Have two interfaces
interface IEmailContravarianceCommunicationTemplate<out TInputData> where TInputData : IEmailTemplateInput
and
interface IEmailCovarianceCommunicationTemplate<out TInputData> where TInputData : IEmailTemplateInput
2) Have RiskPeerReviewNotificationTemplate implement both.
3) Use interface depending on their context