Question

Pour autant que je sache, il n’est pas possible de procéder comme suit en C # 2.0

public class Father
{
    public virtual Father SomePropertyName
    {
        get
        {
            return this;
        }
    }
}

public class Child : Father
{
    public override Child SomePropertyName
    {
        get
        {
            return this;
        }
    }
}

Je résous le problème en créant la propriété dans la classe dérivée sous la forme & "nouveau &"; mais bien sûr, ce n'est pas polymorphe.

public new Child SomePropertyName

Existe-t-il une solution en 2.0? Qu'en est-il des fonctionnalités de la version 3.5 qui traitent de cette question?

Était-ce utile?

La solution

Cela n’est possible dans aucun langage .NET pour des raisons de sécurité du type. Dans les langues compatibles avec le type, vous devez fournir la covariance pour les valeurs de retour et la contravariance pour les paramètres. Prenez ce code:

class B {
    S Get();
    Set(S);
}
class D : B {
    T Get();
    Set(T);
}

Pour les méthodes Get, la covariance signifie que T doit être S ou un type dérivé de D. Sinon, si vous aviez une référence à un objet de type B stocké dans une variable typée B.Get(), lorsque vous appelez Set, vous n'obtiendrez pas d'objet représentable en tant que B.Set(X) détruit le système de types. .

Pour les méthodes X, contravariance signifie que D::Set(T) doit être <=> ou un type dont <=> dérive. Sinon, si vous aviez une référence à un objet de type <=> stocké dans une variable typée <=>, lorsque vous avez appelé <=>, où <=> était de type <=> mais non de type <=>, < => obtiendrait un objet d'un type inattendu.

En C #, il y avait une décision consciente d'empêcher le changement de type en cas de surcharge des propriétés, même lorsqu'elles ne possèdent qu'un seul des paires getter / setter, car elles auraient sinon un comportement très incohérent ( " Vous voulez dire que je peux changer le type de celui qui a un getter, mais pas celui avec à la fois un getter et un setter? Pourquoi pas?!? & "; - Un univers alternatif anonyme débutant).

Autres conseils

Vous pouvez re-déclarer (nouveau), mais vous ne pouvez pas re-déclarer et remplacer en même temps (avec le même nom). Une option consiste à utiliser une méthode protégée pour masquer les détails - ceci permet à la fois le polymorphisme et le masquage:

public class Father
{
    public Father SomePropertyName
    {
        get {
            return SomePropertyImpl();
        }
    }
    protected virtual Father SomePropertyImpl()
    {
        // base-class version
    }
}

public class Child : Father
{
    public new Child SomePropertyName
    {
        get
        { // since we know our local SomePropertyImpl actually returns a Child
            return (Child)SomePropertyImpl();
        }
    }
    protected override Father SomePropertyImpl()
    {
        // do something different, might return a Child
        // but typed as Father for the return
    }
}

Non, mais vous pouvez utiliser des génériques à partir de 2:

public class MyClass<T> where T: Person
{
    public virtual T SomePropertyName
    {
        get
        {
            return  ...;
        }
    }
}

Alors père et enfant sont des versions génériques de la même classe

De Wikipedia :

  

Dans le langage de programmation C #, la prise en charge des deux types de retour   covariance et paramètre   contravariance pour les délégués a été ajouté   dans la version 2.0 du langage.   Ni covariance ni contravariance   sont pris en charge pour le remplacement de méthode.

Cela ne dit explicitement rien sur la covariance des propriétés.

Vous pouvez créer une interface commune pour le père et l'enfant et renvoyer un type de cette interface.

Non. C # ne supporte pas cette idée (elle s'appelle & "; Retourne la covariance de type &";). Vous pouvez cependant faire ceci:

public class FatherProp
{
}

public class ChildProp: FatherProp
{
}


public class Father
{
    public virtual FatherProp SomePropertyName
    {
        get
        {
            return new FatherProp();
        }
    }
}


public class Child : Father
{
    public override FatherProp SomePropertyName
    {
        get
        {
            // override to return a derived type instead
            return new ChildProp();
        }
    }
}

i.e. utilise le contrat défini par la classe de base, mais renvoie un type dérivé. J'ai préparé un exemple plus détaillé pour clarifier ce point - en renvoyant & "This &"; encore une fois ne changerait rien.

Il est possible (mais désordonné) de tester l'objet retourné pour son type réel (c'est-à-dire & "si someObject est ChildProp &"), mais il est préférable d'appeler une méthode virtuelle dessus. la bonne chose pour son type.

La méthode virtuelle de la classe de base (dans ce cas, la propriété virtuelle) comporte non seulement une implémentation, mais définit également un contrat: une classe enfant peut fournir une implémentation différente de SomePropertyName si elle remplit ce contrat (c'est-à-dire que SomePropertyName renvoie un objet de type " FatherProp "). Renvoi d'un objet de type & Quot; ChildProp & Quot; dérivé de " FatherProp " répond à ce contrat. Mais vous ne pouvez pas modifier le contrat dans & Quot; Enfant & Quot; - ce contrat s’applique à toutes les classes issues de & "Père &";

Si vous prenez du recul et examinez votre conception plus large, il est possible que vous souhaitiez également envisager d'autres constructions de langage dans la boîte à outils C #: les génériques ou les interfaces.

  

Non. C # ne supporte pas cette idée   (il s'appelle " type de retour   covariance ").

     

Sur Wikipedia:

     

Dans le langage de programmation C #,   support pour les deux types de retour   covariance et paramètre   contravariance pour les délégués a été ajouté   dans la version 2.0 du langage.   Ni covariance ni contravariance   sont pris en charge pour le remplacement de méthode.

     

Vous pouvez re-déclarer (nouveau), mais vous   ne peut pas re-déclarer et remplacer à la   même heure (avec le même nom). Un   l'option est d'utiliser une méthode protégée pour   masquer les détails - cela permet à la fois   polymorphisme et se cacher en même temps   heure:

La meilleure solution serait d'utiliser des médicaments génériques:

public class MyClass<T> where T: Person
{
   public virtual T SomePropertyNameA
   {        
      get { return  ...; }    
   }
}//Then the Father and Child are generic versions of the same class

C’est le plus proche possible (jusqu’à présent):

    public sealed class JustFather : Father<JustFather> {}

    public class Father<T> where T : Father<T>
    { public virtual T SomePropertyName
        { get { return (T) this; }
        }
    }

    public class Child : Father<Child>
    { public override Child SomePropertyName
        { get { return  this; }
        }
    }

Sans la classe JustFather, vous ne pouvez pas instancier un Father<T> à moins qu'il s'agisse d'un autre type dérivé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top