2016-06-09 1 views
2

J'ai le modèle d'interface de classe suivante sur laquelle je veux utiliser MEF exportation et l'exportation:Pourquoi le modèle Import/Export suivant avec des interfaces n'est pas légal?

public interface IDinosaur 
{ 
    string Species { get; } 
} 

public class Pterodactyl : IDinosaur 
{ 
    public string Species { get; set; } 
    public float WingSpan { get; set; } 
} 

public interface ICage<in T> 
{ 
    void Transport(T animal); 
} 

[Export(typeof(ICage<IDinosaur>))] // <-- This appears a problem 
public class PterodactylCage : ICage<Pterodactyl> 
{ 
    public void Transport(Pterodactyl dinosaur) { } 
} 

public class DinoTransportationService 
{ 
    [Import(AllowDefault = true)] 
    private ICage<IDinosaur> m_dinosaurCage = null; 
} 

Maintenant, je dirais que cela est légal, comme les [Export(typeof(ICage<IDinosaur>))] indeeds exporte la ICage d'un IDinosaur (qui se trouve être un Pterodactyl, mais ceci implémente l'interface de dinosaure alors cela devrait être bien non?). Cependant, cela me donne une CompositionException. disant:

"The export 'PterodactylCage (ContractName=\"ICage(IDinosaur)\")' is not assignable to type 'ICage`1[[IDinosaur, MyProgramme, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'." 

je pourrais corriger cela en changeant l'exportation vers:

[Export(typeof(ICage<Pterodactyl>))] // <-- This is ok 
public class PterodactylCage : ICage<Pterodactyl> 

Et l'importation:

[Import(AllowDefault = true)] 
private ICage<Pterodactyl> m_dinosaurCage = null; 

Sauf, que l'importation devient beaucoup trop spécifique, et En fait, dans mon cas, l'importation se fait dans un assemblage différent qui n'a jamais entendu parler des ptérodactyles, donc c'est une mauvaise solution. Pourquoi le premier exemple n'est pas légal, et quelle est la solution pour ce modèle?

Répondre

2

Ce n'est pas valide parce que (comme message d'erreur indique par ailleurs) instance de PterodactylCage est incessible à ICage<IDinosaur>:

ICage<IDinosaur> cage = new PterodactylCage(); // this won't compile 

Ceci est lié à covariance \ contravariance d'interfaces génériques, vous pouvez lire ce qu'il est à de nombreux endroits sur internet (c'est un large sujet à décrire ici).

Si vous aviez cette définition de l'interface:

public interface ICage<out T> // note "out" keyword 

alors ce serait légal. Cependant, vous ne pouvez pas utiliser le paramètre comme argument dans votre méthode Trasport, cela ne résoudra pas votre problème.

Un peu plus sur pourquoi cela est illégal intuitivement. Supposons que c'était légal. Ensuite, vous avez ICage<IDinosaur> instance avec la méthode Tranport qui accepte IDinosaur. Mais le type sous-jacent est PterodactylCage qui est ICage<Pterodactyl>. Mais vous pouvez passer n'importe quelle instance de IDinosaur à Transport méthode, pas seulement Pterodactyl (rappelez-vous - nous travaillons avec ICage<IDinosaur>), ce qui nous amène à la contradiction. C'est pourquoi intuitivement ce n'est pas légal.

+0

Merci, cette explication est en effet une bonne explication de pourquoi ce qui précède n'est pas légal. Y at-il une alternative qui rend ce que je veux faire cependant? – Yellow

+0

Bien ICage n'est pas ICage dans votre cas. Si vous réussissez d'une façon ou d'une autre à exporter et que quelqu'un a passé Theropods dans votre méthode de transport, il échouera lors de l'exécution. Donc, vous devriez revoir votre logique parce que ce que vous essayez de faire est tout simplement faux. – Evk

+0

Mais vous pouvez implémenter ICage au lieu de ICage et l'exporter. Vous pouvez vérifier à l'intérieur de la méthode de transport quel genre d'objet a été passé en IDinosaur ici (parce que cela peut être n'importe quel dinosaure à nouveau). – Evk