91 votes

Est-ce que C# prend en charge le type de retour de la covariance?

Je travaille avec le .NET framework et je veux vraiment être en mesure de personnaliser un type de page que l'ensemble de mon site utilise des. Le problème vient quand je suis en train d'essayer d'accéder à la page à partir d'un contrôle. Je veux être en mesure de retourner à mon type spécifique de la page au lieu de la page par défaut. Est-il possible de faire cela?

public class MyPage : Page
{
// My own logic
}

public class MyControl : Control
{
    public MyPage Page {get; set;}
}

179voto

Eric Lippert Points 300275

Cela ressemble à ce que vous voulez, c'est le type de retour de la covariance. C# ne prend pas en charge le type de retour de la covariance.

Le type de retour de la covariance est l'endroit où vous substituez une méthode de classe de base qui renvoie moins à un type spécifique avec l'un qui renvoie un plus spécifique:

abstract class Enclosure
{
    public abstract Animal Contents();
}
class Aquarium : Enclosure
{
    public override Fish Contents() { ... }
}

C'est sûr, parce que les consommateurs de Contenu via le Boîtier s'attendre à un Animal, et l'Aquarium promet non seulement de satisfaire à cette condition, mais en outre de rendre plus stricte promesse: que l'animal est toujours un poisson.

Ce genre de covariance n'est pas pris en charge en C#, et il est peu probable d'être toujours pris en charge. Il n'est pas pris en charge par le CLR. (Il est pris en charge par le C++ et le C++/CLI mise en œuvre sur le CLR; il le fait en générant magique méthodes d'assistance de la sorte, je suggère ci-dessous.)

(Certains d'appui aux langues paramètre formel de type contravariance ainsi, que vous pouvez remplacer une méthode qui prend un Poisson avec une méthode qui prend un Animal. Encore une fois, le contrat est rempli; la classe de base exige que tous les Poissons doivent être manipulés, et la classe dérivée promet non seulement de manipuler les poissons, mais n'importe quel animal. De même, le C# et le CLR ne prennent pas en charge le paramètre formel de type contravariance.)

La façon dont vous pouvez contourner cette limitation est de faire quelque chose comme:

abstract class Enclosure
{
    protected abstract Animal GetContents();
    public Animal Contents() { return this.GetContents(); }
}
class Aquarium : Enclosure
{
    protected override Animal GetContents() { return this.Contents(); }
    public new Fish Contents() { ... }
}

Maintenant, vous obtenez à la fois les avantages du remplacement d'une méthode virtuelle, de plus en plus à taper lors de l'utilisation de quelque chose de la compilation type d'Aquarium.

2voto

Zhais Points 701

Placer cela dans le MyControl objet de travail:

 public new MyPage Page {get return (MyPage)Page; set;}'

Vous ne pouvez pas remplacer la propriété parce qu'elle renvoie un type différent... mais vous pouvez la redéfinir.

Vous n'avez pas besoin de covariance dans cet exemple, puisqu'il est relativement simple. Tout ce que vous faites est d'hériter de l'objet de base Page de MyPage. Tout Control que vous souhaitez renvoyer MyPage au lieu de Page des besoins de redéfinir l' Page de la propriété de l' Control

1voto

Cade Roux Points 53870

Oui, il prend en charge la covariance, mais il dépend de la chose exacte que vous essayez d'atteindre.

J'ai aussi tendance à utiliser des génériques beaucoup de choses, ce qui signifie que lorsque vous faites quelque chose comme:

class X<T> {
    T doSomething() {
    }

}

class Y : X<Y> {
    Y doSomethingElse() {
    }
}

var Y y = new Y();
y = y.doSomething().doSomethingElse();

Et de ne pas "perdre" votre types.

0voto

Hogan Points 30189

Vous pouvez accéder à votre page de contrôle de la marche jusqu'à l'arbre-mère. C'est

myParent = this;

while(myParent.parent != null)
  myParent = myParent.parent;

*Ne pas compiler ou de test.

Ou obtenir la page parent dans le contexte actuel (dépend de votre version).


Alors ce que j'aimerais faire, c'est ceci: j'ai créer une interface avec les fonctions que je veux utiliser le contrôle (par exemple IHostingPage)

Puis je lance la page parent 'IHostingPage host = (IHostingPage)Parent; et je suis tous ensemble à l'appel de la fonction sur la page j'ai besoin de mon contrôle.

0voto

AGoodDisplayName Points 1954

Je n'ai pas essayé, mais n'est-ce pas le travail?

YourPageType myPage = (YourPageType)yourControl.Page;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X