7

我正在尝试实施一种策略模式,以允许我将一些“好处”应用于“帐户”。在下面的代码中,我无法将接口的实现添加到期望该接口的字典中。我认为这是某种逆变问题,但感觉我应该能够做到这一点:

编辑:
由于答案似乎是不可能的,关于如何实现我在这里的目标有什么建议吗?

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");
    }
}
4

3 回答 3

1

请参阅:协变和逆变常见问题解答

如何自己创建变体通用接口和委托?

out 关键字将类型参数标记为协变,而 in 关键字将其标记为逆变。要记住的两个最重要的规则:
    如果泛型类型参数仅用作方法返回类型而不用作形式方法参数的类型,则可以将其标记为协变。
    反之亦然,如果一个类型仅用作形式方法参数的类型而不用作方法返回类型,则可以将其标记为逆变。
于 2011-05-07T02:27:37.430 回答
1

您需要将 T 添加到您的界面:

public interface IBenefitStrategy<in T>
于 2011-05-07T02:27:56.267 回答
1

已编辑 - 格式化引擎已删除 中的所有内容<angled brackets>,这使得它相当难以理解。对不起,如果这令人困惑!

FreeBenefitStrategy实现IBenefitStrategy<FreeBenefit>。它只能适用FreeBenefits,不能适用任何其他类型的福利。它不是IBenefitStrategy<BenefitBase>,所以你不能把它放在那些的集合中。从逻辑上讲,IBenefiteStrategy可能是逆变的BenefitBase,但这在这里对您没有帮助-IBenefitStrategy<BenefitBase>声称能够应用各种好处,因此IBenefitStrategy<BenefitBase>is-an IBenefitStrategy<FreeBenefit>,但反之则不正确- anIBenefitStrategy<FreeBenefit>不能应用任何BenefitBase

我认为没有任何方法可以在不使用类型转换的情况下拥有您想要的异构集合。如果您考虑一下,除了它们从对象共享的方法之外,没有任何方法可以在 anIBenefitStrategy<FreeBenefit>和 an上调用IBenefitStrategy<ExpensiveBenefit>,因此 object 类型的变量是唯一可以指向其中任何一个的东西是有道理的。如果要将它们保存在同一个字典中,则需要将其设为Dictionary<Type, object>. 您可以更改GetStrategy为泛型并应用适当的类型转换,但在查找字典时要小心 - 想想如果传入的对象是FreeBenefit.

于 2011-05-07T03:59:17.420 回答