7 Stimmen

Problem der unveränderlichen Vererbung

Ich versuche, ein Strategiemuster zu implementieren, um mir zu ermöglichen, einen "Nutzen" auf ein "Konto" anzuwenden. Im folgenden Code kann ich meine Implementierung einer Schnittstelle nicht in ein Wörterbuch einfügen, das die Schnittstelle erwartet. Ich denke, es ist eine Art von Kontravarianz Problem, aber es fühlt sich wie ich sollte in der Lage sein, dies zu tun:

EDITAR:
Da die Antwort zu sein scheint, dass es einfach nicht möglich ist, irgendwelche Vorschläge, wie man zu erreichen, was ich hier anstrebe?

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

1voto

helloworld922 Punkte 10543

Voir : Kovarianz und Kontravarianz FAQ

How can I create variant generic interfaces and delegates myself?

The out keyword marks a type parameter as covariant, and the in keyword marks it as contravariant. The two most important rules to remember:
    You can mark a generic type parameter as covariant if it is used only as a method return type and is not used as a type of formal method parameters.
    And vice versa, you can mark a type as contravariant if it is used only as a type of formal method parameters and not used as a method return type.

1voto

Tejs Punkte 39916

Sie müssen Ihrer Schnittstelle den Ausgang T hinzufügen:

public interface IBenefitStrategy<in T>

1voto

Weeble Punkte 15723

BEARBEITET - Die Formatierungsmaschine hatte alles entfernt, was in <angled brackets> was es ziemlich unmöglich machte, sie zu verstehen. Tut mir leid, wenn das verwirrend war!

FreeBenefitStrategy implementiert IBenefitStrategy<FreeBenefit> . Sie kann nur gelten FreeBenefits und nicht irgendeine andere Art von Leistung. Es ist keine IBenefitStrategy<BenefitBase> Sie können es also nicht in eine solche Sammlung aufnehmen. Das ist logisch, IBenefiteStrategy könnte kontravariant sein in BenefitBase aber das hilft Ihnen hier nicht weiter - ein IBenefitStrategy<BenefitBase> behauptet, anwenden zu können todos Arten von Vorteilen, so dass ein IBenefitStrategy<BenefitBase> ist-ein IBenefitStrategy<FreeBenefit> , aber das Gegenteil ist nicht der Fall - ein IBenefitStrategy<FreeBenefit> kann keine BenefitBase .

Ich glaube nicht, dass es eine Möglichkeit gibt, eine heterogene Sammlung zu haben, wie Sie es wünschen, ohne Typisierung zu verwenden. Wenn Sie darüber nachdenken, gibt es keine Methode, die Sie sowohl für eine IBenefitStrategy<FreeBenefit> und ein IBenefitStrategy<ExpensiveBenefit> jenseits derer, die sie von object gemeinsam haben, so dass es sinnvoll ist, dass eine Variable vom Typ object das einzige Ding ist, das auf eines von beiden zeigen kann. Wenn Sie sie im gleichen Wörterbuch behalten wollen, müssen Sie sie zu einer Dictionary<Type, object> . Sie könnten ändern GetStrategy generisch zu sein und eine angemessene Typisierung vorzunehmen, aber seien Sie vorsichtig, wenn Sie Ihr Wörterbuch nachschlagen - überlegen Sie, was passiert, wenn das übergebene Objekt einer Unterklasse von FreeBenefit .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X