sco*_*ttm 7 c# casting contravariance
我正在尝试实施一种策略模式,允许我允许我对"帐户"应用一些"好处".在下面的代码中,我无法将我的接口实现添加到期望接口的字典中.我认为这是一种逆变问题,但感觉我应该能够做到这一点:
编辑:
既然答案似乎是不可能的,有关如何实现我的目标的任何建议吗?
void Main()
{
var provider = new BenefitStrategyProvider();
var freeBenefit = new FreeBenefit();
var strategy = provider.GetStrategy(freeBenefit);
strategy.ApplyBenefit(freeBenefit, new Account());
}
public class BenefitStrategyProvider
{
private Dictionary<Type, IBenefitStrategy<BenefitBase>> _strategies = new Dictionary<Type, IBenefitStrategy<BenefitBase>>();
public BenefitStrategyProvider()
{
/* Why can't I add this? */
_strategies.Add(typeof(FreeBenefit), new FreeBenefitStrategy());
}
public IBenefitStrategy<BenefitBase> GetStrategy(BenefitBase benefit)
{
return _strategies[benefit.GetType()];
}
}
public class Account {}
public abstract class BenefitBase
{
public string BenefitName {get;set;}
}
public class FreeBenefit : BenefitBase {}
public interface IBenefitStrategy<T> where T: BenefitBase
{
void ApplyBenefit(T benefit, Account account);
}
public class FreeBenefitStrategy : IBenefitStrategy<FreeBenefit>
{
public void ApplyBenefit(FreeBenefit benefit, Account account)
{
Console.WriteLine("Free Benefit applied");
}
}
Run Code Online (Sandbox Code Playgroud)
编辑 - 格式化引擎已删除 中的所有内容<angled brackets>,这使得它变得相当难以理解。抱歉,如果这令人困惑!
FreeBenefitStrategy实现IBenefitStrategy<FreeBenefit>. 它只能适用FreeBenefits,不能适用任何其他种类的福利。它不是IBenefitStrategy<BenefitBase>,因此您不能将其放入其中的集合中。从逻辑上讲,IBenefiteStrategy可能是逆变的BenefitBase,但这对您没有帮助 - anIBenefitStrategy<BenefitBase>声称能够应用各种好处,因此IBenefitStrategy<BenefitBase>is-an IBenefitStrategy<FreeBenefit>,但反之则不然 - anIBenefitStrategy<FreeBenefit>不能应用任何BenefitBase。
我认为没有任何方法可以在不使用类型转换的情况下拥有您想要的异构集合。如果您考虑一下,除了它们从对象共享的方法之外,没有任何方法可以在 anIBenefitStrategy<FreeBenefit>和 an上调用IBenefitStrategy<ExpensiveBenefit>,因此对象类型的变量是唯一可以指向其中任何一个的东西是有道理的。如果您想将它们保留在同一字典中,则需要将其设为Dictionary<Type, object>. 您可以更改GetStrategy为泛型并应用适当的类型转换,但在查找字典时要小心 - 想想如果传入的对象是 的子类会发生什么FreeBenefit。