7
votes

Convertir le paramètre générique avec «où» de type contrainte n'est pas possible?

J'ai une classe de base: xxx pré>

et une classe qui stocke les références code> DomainEventsSUCCREDER p> xxx pré>

Même si le type de méthode code> code> est contraint, je ne peux pas convertir de Domaineventsubscriber Abonné code> où T: DomainEvent code> à DomaineVentsUscriber Code>: P>

eventSubscriber = (DomainEventSubscriber<DomainEvent>)subscriber;


5 commentaires

Vous avez besoin d'une interface avec une valeur . Je ne sais pas si vous pouvez le faire ici.


Néanmoins, il vaut la peine de coller un out dans DomainevomSubscriber Où T: DomaineEvent Pour voir si cela fonctionne.


@Matthewwatson qui sera jamais travail depuis out et dans Les modificateurs de type générique ne peuvent être utilisés que avec des interfaces, pas des classes .


@VirtLink Fair assez, peut-être qu'il pourrait essayer de faire une interface!


Votre conception est défectueux. Vous essayez de vous donner la capacité de pouvoir envoyer une instance Simple DomainEvent à GUESSEvent (MydomainEvent) Méthode, qui ne fonctionnera jamais. Le compilateur a fait du bon travail en vous protégeant de cela.


3 Réponses :


5
votes

Covariance

Vous avez besoin d'une interface avec un paramètre de type covariant t code> pour pouvoir le jeter à un type de base de t code>. Par exemple, ienumerable code> est une telle interface. Notez le mot-clé out code>, ce qui signifie t code> est covariant et peut donc uniquement apparaître dans les positions sortie em> (par exemple, valeurs de retour et getters). À cause de la covariance, vous pouvez lancer un iEnumerable code> à ienumerable code>: une séquence énumérable de dauphins est sûrement une séquence énumérable de mammifères. P>

Contravariance h3>

Cependant, vous ne pouvez pas faire Domaineventsubscriber code> une interface IdomainevationsSUCCRITER code> comme t code> t code> Apparaît ensuite dans la position em> entrée em> de gureVent code>. Vous pouvez en faire une interface idomainevientsubscriber code>. P>

Note le mot clé code> dans code>, ce qui signifie t code> est Contravariant em> et peut seulement apparaître dans les positions Entrée em> (par exemple, comme paramètres de la méthode). Par exemple, IequalityComparer code> est une telle interface. En raison de la contrevenance, vous pouvez lancer un IequalityComparer Code> à IéqualityComparer Code>: Si cela peut comparer les mammifères, il peut sûrement comparer les dauphins tels qu'ils sont des mammifères.

Mais cela ne résout également pas votre problème car vous ne pouvez pas lancer un paramètre de type Contravariant uniquement sur un type dérivé plus em> et que vous souhaitez la jeter au type de base. P>


Solution h3>

Je vous conseille de créer une interface code> non générique code> et dérivez votre classe actuelle à partir de celle: P>

public class DomainEventPublisher
{
    private List<IDomainEventSubscriber> subscribers;

    public void Subscribe<T>(DomainEventSubscriber<T> subscriber)
        where T : DomainEvent
    {
        if (!this.Publishing)
        {
            this.subscribers.Add(eventSubscriber);
        }
    }
}


0 commentaires

1
votes

Voici une prise légèrement différente à l'aide d'une interface:

public class DomainEvent
{
}

// The 'in' isn't actually needed to make this work, but it can be added anyway:

public interface IDomainEventSubscriber<in T> where T: DomainEvent
{
    void HandleEvent(T domainEvent);
    Type SubscribedToEventType();
}

public abstract class DomainEventSubscriber<T>: IDomainEventSubscriber<T> where T: DomainEvent
{
    public abstract void HandleEvent(T domainEvent);
    public Type SubscribedToEventType()
    {
        return typeof(T);
    }
}

public class DomainEventPublisher
{
    private List<DomainEventSubscriber<DomainEvent>> subscribers;

    public void Subscribe<T>(IDomainEventSubscriber<T> subscriber)
        where T: DomainEvent
    {
        DomainEventSubscriber<DomainEvent> eventSubscriber;
        eventSubscriber = (DomainEventSubscriber<DomainEvent>)subscriber;

        if (!this.Publishing)
        {
            this.subscribers.Add(eventSubscriber);
        }
    }
}


0 commentaires

3
votes

Il y a de bonnes réponses pour la solution, ici, je sors un peu pour la simple raison pour laquelle vous ne pouvez pas le faire fonctionner.

Les classes de base génériques peuvent être héritées, cependant, avec différents paramètres de type ne sont que des classes différentes. Considérons Liste code> et list code>. Bien qu'ils aient tous deux la définition générique de list`1 code>, mais ils prennent différents paramètres de type; Aucun d'entre eux n'est la classe de base de l'autre. Quelle est votre méthode, serait comme suit: p> xxx pré>

Ceci ne compilerait pas, et même que vous modifiez la déclaration de compilée, comme: P>

public void Subscribe<T>(List<T> subscriber) where T: struct {
    var eventSubscriber=(List<int>)(subscriber as object);

    // ... 
}


0 commentaires