Domanda

Per quanto ne so non è possibile effettuare le seguenti operazioni in C # 2.0

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

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

Ho risolto il problema creando la proprietà nella classe derivata come " new " ;, ma ovviamente questo non è polimorfico.

public new Child SomePropertyName

C'è qualche soluzione in 2.0? Che dire delle funzionalità in 3.5 che affrontano questa questione?

È stato utile?

Soluzione

Questo non è possibile in nessun linguaggio .NET a causa di problemi di sicurezza del tipo. Nei linguaggi sicuri per i tipi, è necessario fornire covarianza per i valori di ritorno e contravarianza per i parametri. Prendi questo codice:

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

Per i metodi Get, covarianza significa che T deve essere S o un tipo derivato da D. Altrimenti, se avessi un riferimento a un oggetto di tipo B memorizzato in una variabile digitata B.Get(), quando avessi chiamato Set non avresti ottenuto un oggetto rappresentabile come B.Set(X) back - rompendo il sistema di tipi .

Per i metodi X, la contraddizione significa che D::Set(T) deve essere <=> o un tipo da cui <=> deriva. Altrimenti, se avevi un riferimento a un oggetto di tipo <=> memorizzato in una variabile digitata <=>, quando hai chiamato <=>, dove <=> era di tipo <=> ma non di tipo <=>, < => otterrebbe un oggetto di un tipo che non si aspettava.

In C #, c'è stata una decisione consapevole di non consentire la modifica del tipo quando si sovraccaricavano le proprietà, anche quando avevano solo una coppia getter / setter, perché altrimenti avrebbe un comportamento molto incoerente ( " Vuoi dire, posso cambiare il tipo su quello con un getter, ma non uno sia con un getter che con un setter? Perché no?!? & Quot; - Anonimo Alternativo Newbie).

Altri suggerimenti

Puoi ri-dichiarare (nuovo), ma non puoi ri-dichiarare e sovrascrivere allo stesso tempo (con lo stesso nome). Un'opzione è utilizzare un metodo protetto per nascondere i dettagli: ciò consente sia il polimorfismo che il nascondersi allo stesso tempo:

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
    }
}

No, ma puoi utilizzare generics in 2 e versioni successive:

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

Quindi Father and Child sono versioni generiche della stessa classe

Da Wikipedia :

  

Nel linguaggio di programmazione C #, supporto per entrambi i tipi di ritorno   covarianza e parametro   è stata aggiunta la contraddizione per i delegati   nella versione 2.0 della lingua.   Né covarianza né contraddizione   sono supportati per l'override del metodo.

Tuttavia non dice esplicitamente nulla sulla covarianza delle proprietà.

Puoi creare un'interfaccia comune per padre e figlio e restituire un tipo di tale interfaccia.

No. C # non supporta questa idea (si chiama & Quot; return type covariance & Quot;). Puoi comunque farlo:

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

vale a dire. usa il contratto definito dalla classe base, ma restituisce un tipo derivato. Ho fatto un esempio più dettagliato per chiarire questo punto: restituendo & Quot; questo & Quot; di nuovo non cambierebbe nulla.

È possibile (ma disordinato) testare l'oggetto restituito per il suo tipo effettivo (cioè " se someObject è ChildProp "), ma è meglio chiamare un metodo virtuale su di esso che lo fa la cosa giusta per il suo tipo.

Il metodo virtuale della classe base (in questo caso, proprietà virtuale) non solo ha un'implementazione, ma definisce anche un contratto: che una classe figlio può fornire un'implementazione diversa di SomePropertyName se soddisfa questo contratto (ovvero SomePropertyName restituisce un oggetto di tipo " FatherProp "). Restituzione di un oggetto di tipo & Quot; ChildProp & Quot; derivato da " FatherProp " soddisfa questo contratto. Ma non puoi modificare il contratto tra & Quot; Child & Quot; - questo contratto si applica a tutte le classi discendenti da " Father " ;.

Se fai un passo indietro e osservi il tuo design più ampio, ci sono altri costrutti di linguaggio nel toolkit C # a cui potresti anche voler pensare: Generics o interfacce.

  

No. C # non supporta questa idea   (si chiama " tipo di ritorno   covarianza quot &;).

     

Da Wikipedia:

     

Nel linguaggio di programmazione C #,   supporto per entrambi i tipi di ritorno   covarianza e parametro   è stata aggiunta la contraddizione per i delegati   nella versione 2.0 della lingua.   Né covarianza né contraddizione   sono supportati per l'override del metodo.

     

Puoi ri-dichiarare (nuovo), ma tu   non è possibile ri-dichiarare e sovrascrivere in   stesso tempo (con lo stesso nome). Uno   l'opzione è utilizzare un metodo protetto per   nascondi i dettagli - questo consente entrambi   polimorfismo e nascondersi allo stesso   tempo:

Le migliori soluzioni sarebbero usare generici:

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

Questo è il più vicino che potrei venire (finora):

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

Senza la classe JustFather, non è possibile creare un'istanza di Father<T> se non fosse un altro tipo derivato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top