Domanda

Non sono sicuro se questa è una cosa strana da fare o no, o se è in qualche modo odore di codice ... ma mi chiedevo se ci fosse un modo (una sorta di modello di oop sarebbe bello) per " Cast " un tipo di base in una forma del suo tipo derivato. So che questo ha poco senso in quanto il tipo derivato avrà funzionalità aggiuntive che il genitore non offre, il che non è fondamentalmente sano. Ma c'è un modo per farlo? Ecco un esempio di codice per consentirci di spiegare meglio cosa sto chiedendo.

public class SomeBaseClass {
    public string GetBaseClassName {get;set;}
    public bool BooleanEvaluator {get;set;}
}

public class SomeDerivedClass : SomeBaseClass {
    public void Insert(SqlConnection connection) {
          //...random connection stuff
          cmd.Parameters["IsItTrue"].Value = this.BooleanEvalutar;
          //...
    }
}

public static void Main(object[] args) {
    SomeBaseClass baseClass = new SomeBaseClass();
    SomeDerivedClass derClass = (SomeDerivedClass)baseClass; 
    derClass.Insert(new sqlConnection());
}

So che sembra sciocco, ma c'è un modo per realizzare qualcosa del genere?

È stato utile?

Soluzione

Non in modo corretto, in " gestito " le lingue. Questo è downcasting e non esiste un modo logico per gestirlo, esattamente per il motivo che hai descritto (le sottoclassi forniscono più delle classi di base - da dove proviene questo "più"?). Se vuoi davvero un comportamento simile per una particolare gerarchia, potresti usare costruttori per tipi derivati ??che prenderanno il tipo base come prototipo.

Si potrebbe costruire qualcosa con la riflessione che gestisca i casi semplici (tipi più specifici che non hanno uno stato di addizione). In generale, basta riprogettare per evitare il problema.

Modifica: Woops, impossibile scrivere operatori di conversione tra tipi di base / derivati. Una stranezza di Microsoft che cerca di "proteggerti" contro te stesso. Ah bene, almeno non sono affatto così male come il sole.

Altri suggerimenti

Prova la composizione anziché l'eredità!

Mi sembra che faresti meglio a passare un'istanza di SomeBaseClass a SomeDerivedClass (che non deriverà più dalla classe base e dovrebbe essere rinominata come tale)

public class BooleanHolder{       
    public bool BooleanEvaluator {get;set;}
}

public class DatabaseInserter{
    BooleanHolder holder;

    public DatabaseInserter(BooleanHolder holder){
        this.holder = holder;
    }

    public void Insert(SqlConnection connection) {
          ...random connection stuff
          cmd.Parameters["IsItTrue"].Value = holder.BooleanEvalutar;
          ...
    }
}

public static void Main(object[] args) {
    BooleanHolder h = new BooleanHolder();
    DatabaseInserter derClass = new DatabaseInserter(h);
    derClass.Insert(new sqlConnection);
}

Guarda http: //www.javaworld. com / javaworld / jw-11-1998 / jw-11-technologies.html (pagina 3):

  

Riutilizzo del codice tramite composizione Composizione   fornisce un modo alternativo per Apple   riutilizzare l'implementazione di Fruit di   sbucciare(). Invece di estendere Fruit,   La mela può contenere un riferimento a un frutto   istanza e definire il proprio peel ()   metodo che invoca semplicemente peel () su   il frutto.

Personalmente non penso che valga la pena di usare Eredità in questo caso. Passa invece l'istanza della classe base nel costruttore e accedervi tramite una variabile membro.

private class ExtendedClass //: BaseClass - like to inherit but can't
{
    public readonly BaseClass bc = null;
    public ExtendedClass(BaseClass b)
    {
        this.bc = b;
    }

    public int ExtendedProperty
    {
        get
        {
        }
    }
}

Il downcasting ha senso, se si dispone di un oggetto di classe derivata ma a cui fa riferimento un riferimento al tipo di classe di base e per qualche motivo si desidera che venga fatto riferimento a un riferimento al tipo di classe derivata. In altre parole, è possibile eseguire il downcast per annullare l'effetto del precedente upcasting. Ma non puoi avere un oggetto della classe base a cui fa riferimento un riferimento di un tipo di classe derivata.

Non sto dicendo che lo consiglio. Ma potresti trasformare la classe base in stringa JSON e poi convertirla nella classe derivata.

SomeDerivedClass layer = JsonConvert.DeserializeObject<SomeDerivedClass>(JsonConvert.SerializeObject(BaseClassObject));

No, questo non è possibile. In un linguaggio gestito come C #, semplicemente non funzionerà. Il runtime non lo consentirà, anche se il compilatore lo lascia passare.

Ti sei detto che sembra sciocco:

SomeBaseClass class = new SomeBaseClass();
SomeDerivedClass derClass = (SomeDerivedClass)class; 

Quindi chiediti, class è in realtà un'istanza di SomeDerivedClass ? No, quindi la conversione non ha senso. Se devi convertire SomeBaseClass in SomeDerivedClass , devi fornire un qualche tipo di conversione, un costruttore o un metodo di conversione.

Sembra però che la gerarchia della tua classe abbia bisogno di lavoro. In generale, non dovrebbe essere possibile convertire un'istanza di classe base in un'istanza di classe derivata. Generalmente dovrebbero esserci dati e / o funzionalità che non si applicano alla classe base. Se la funzionalità della classe derivata si applica a tutte le istanze della classe base, allora dovrebbe essere arrotolata nella classe base o estratta in una nuova classe che non fa parte della gerarchia della classe base.

Il linguaggio C # non consente tali operatori, ma puoi comunque scriverli e funzionano:

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Implicit(Base a) { ... }

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Explicit(Base a) { ... }

Sì, questo è un odore di codice e praticamente inchioda il fatto che la tua catena ereditaria è rotta.

La mia ipotesi (dall'esempio limitato) è che preferiresti far funzionare DerivedClass su un'istanza di SomeBaseClass - in modo che " DerivedClass abbia SomeBaseClass " ;, anziché " DerivedClass è SomeBaseClass " ;. Questo è noto come "favorire la composizione rispetto all'eredità".

Come altri hanno notato, il casting che suggerisci non è davvero possibile. Potrebbe essere un caso in cui Decorator pattern (Head First extract) può essere introdotto?

Hai pensato a un'interfaccia che la tua classe base e la tua classe derivata implementerebbero entrambe? Non conosco i dettagli del perché stai implementando in questo modo, ma potrebbe funzionare.

Questo si chiama downcasting e il suggerimento di Seldaek di usare il "sicuro" la versione è valida.

Ecco una descrizione abbastanza decente con esempi di codice .

Questo non è possibile perché come hai intenzione di ottenere il " extra " che ha la classe derivata. Come farà il compilatore a sapere che intendi derivatoClass1 e non derivatoClass2 quando lo installi?

Penso che quello che stai veramente cercando sia il modello di fabbrica o simile, quindi puoi istanziare oggetti senza conoscere veramente il tipo esplicito che viene istanziato. Nel tuo esempio, avendo " Inserisci " Il metodo sarebbe un'interfaccia che l'istanza restituita dalla fabbrica implementa.

Non so perché nessuno abbia detto questo e potrei essermi perso qualcosa, ma puoi usare la parola chiave as e se devi fare una dichiarazione if usa if.

SomeDerivedClass derClass = class as SomeDerivedClass; //derClass is null if it isnt SomeDerivedClass
if(class is SomeDerivedClass)
    ;

-edit- Ho fatto questa domanda molto tempo fa

Di recente ho avuto bisogno di estendere un semplice DTO con un tipo derivato per aggiungere altre proprietà su di esso. Volevo quindi riutilizzare la logica di conversione che avevo, dai tipi di database interni ai DTO.

Il modo in cui l'ho risolto è stato imponendo un costruttore vuoto sulle classi DTO, usandolo in questo modo:

class InternalDbType {
    public string Name { get; set; }
    public DateTime Date { get; set; }
    // Many more properties here...
}

class SimpleDTO {
    public string Name { get; set; }
    // Many more properties here...
}

class ComplexDTO : SimpleDTO {
    public string Date { get; set; }
}

static class InternalDbTypeExtensions {
    public static TDto ToDto<TDto>(this InternalDbType obj) where TDto : SimpleDTO, new() {
        var dto = new TDto {
            Name = obj.Name
        }
    }
}

Posso quindi riutilizzare la logica di conversione dal semplice DTO durante la conversione in quella complessa. Certo, dovrò compilare le proprietà del tipo complesso in qualche altro modo, ma con molte, molte proprietà del semplice DTO, questo semplifica davvero le cose dell'IMO.

Non può funzionare. Vai a consultare la pagina di aiuto collegata dall'errore di compilazione.

La soluzione migliore è utilizzare qui i metodi di fabbrica.

Come hanno indicato molte risposte, non è possibile effettuare il downcast, il che ha perfettamente senso.

Tuttavia, nel tuo caso, SomeDerivedClass non ha proprietà che saranno "mancanti". Quindi potresti creare un metodo di estensione come questo:

public static T ToDerived<T>(this SomeBaseClass baseClass) 
    where T:SomeBaseClass, new()
{
    return new T()
    {
        BooleanEvaluator = baseClass.BooleanEvaluator,
        GetBaseClassName = baseClass.GetBaseClassName
    };
}

Quindi non stai lanciando, stai solo convertendo:

SomeBaseClass b = new SomeBaseClass();
SomeDerivedClass c = b.ToDerived<SomeDerivedClass>();

Funziona davvero solo se tutti i dati nella classe base sono sotto forma di proprietà leggibili e scrivibili.

C ++ lo gestisce usando un costruttore. C ++ Typecasting . Mi sembra una svista. Molti di voi hanno sollevato il problema di cosa farebbe il processo con le proprietà extra. Vorrei rispondere, cosa fa il compilatore quando crea la classe derivata quando il programmatore non imposta le proprietà? Ho gestito questa situazione in modo simile al C ++. Creo un costruttore che accetta la classe di base, quindi imposta manualmente le proprietà nel costruttore. Questo è sicuramente preferibile per impostare una variabile nella classe derivata e interrompere l'ereditarietà. Vorrei anche scegliere un metodo di fabbrica perché penso che il codice risultante sarebbe più pulito.

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