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 キーワードはそれを反変としてマークします。覚えておくべき 2 つの最も重要なルール:
    メソッドの戻り値の型としてのみ使用され、正式なメソッド パラメーターの型としては使用されない場合は、ジェネリック型パラメーターを共変としてマークできます。
    逆に、型が正式なメソッド パラメーターの型としてのみ使用され、メソッドの戻り値の型として使用されない場合は、その型を反変としてマークできます。
于 2011-05-07T02:27:37.430 に答える
1

インターフェイスに T を追加する必要があります。

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

EDITED - フォーマット エンジンが のすべてを削除した<angled brackets>ため、理解がかなり不可能になりました。これが紛らわしかったらごめんなさい!

FreeBenefitStrategy実装しIBenefitStrategy<FreeBenefit>ます。のみ適用できFreeBenefits、他の種類の特典は適用されません。ではないIBenefitStrategy<BenefitBase>ので、それらのコレクションに入れることはできません。論理的にIBenefiteStrategyは で反変である可能性がありますBenefitBaseが、これはここでは役に立ちません。a はあらゆる種類の利点IBenefitStrategy<BenefitBase>を適用できると主張しているため、 is-anですが、逆は真ではありません。an は適用できません。IBenefitStrategy<BenefitBase>IBenefitStrategy<FreeBenefit>IBenefitStrategy<FreeBenefit>BenefitBase

型キャストを使わずに、あなたが望むような異種コレクションを持つ方法はないと思います。考えてみると、オブジェクトから共有されているものとそれ以外のものIBenefitStrategy<FreeBenefit>の両方で呼び出すことができるメソッドはありません。IBenefitStrategy<ExpensiveBenefit>それらを同じ辞書に保持したい場合は、Dictionary<Type, object>. ジェネリックに変更GetStrategyして適切な型キャストを適用することもできますが、辞書を検索するときは注意してください。渡されたオブジェクトが のサブクラスである場合に何が起こるかを考えてくださいFreeBenefit

于 2011-05-07T03:59:17.420 に答える