Quando ha senso implementare l'operatore esplicito C #?

3

Follow-up di Il mio utilizzo dell'operatore di casting esplicito è ragionevole o un brutto attacco?

Uno degli utenti che ha commentato quella domanda ha detto che è davvero brutto se l'operatore di casting crea un nuovo oggetto sotto il cofano, poiché cessa di essere un cast reale. È ovviamente un punto molto valido.

Quando si userebbe la capacità di definire la conversione del tipo personalizzato? In particolare: tra due tipi che non sono correlati per ereditarietà in alcun modo.

Con gli oggetti correlati rende (alcuni) senso:

class Animal {
    public string Name {get;set;}
    public int Age {get;set;}
}

class Dog : Animal {
    public void Bark(){}
    public void Fetch(){}
}

class Cat : Animal {
    public void Meow(){}
    public void Sleep(){}
}

Anche se normalmente la conversione di Cat in Dog non sarebbe possibile, ha senso autorizzarla esplicitamente - condividono tutti i loro dati, solo il comportamento è diverso.

Anche quando ci sarebbe qualche differenza nei campi:

class Parrot : Animal {
    public int WingSpan {get;set;}

    public void Screech(){}
}

il casting potrebbe ancora essere desiderato (% da% di% a% di% di latitudine per esempio, poiché Parrot non ha più dati di Cat ).

Ma per quanto riguarda due tipi non correlati? È possibile fare:

class Rock{
    public int Age {get;set;}
}

e

public static explicit operator Rock(Cat cat){
    return new Rock{Age = cat.Age};
}

ma perché? Come indicato nella domanda correlata, causerebbe un comportamento abbastanza strano:

var cat = new Cat{Name = "Fluffy", Age = 8};
var rock = (Rock) cat;
rock.Age = 100000000;
Console.WriteLine(rock.Age); // 100000000
Console.WriteLine(cat.Age); // 8

Qualcuno può dare un buon esempio di quando implementare un operatore esplicito tra tipi non correlati ha senso e come farlo?

    
posta Gerino 05.05.2015 - 16:38
fonte

2 risposte

8

Can anyone give a good example of when implementing explicit operator between unrelated types makes sense and how to do it?

Sosterrò che mai ha senso sovraccaricare l'operatore di conversione esplicita. Quell'operatore ha un comportamento ben definito e usandolo per un comportamento diverso, sempre cadrà nel regno di "intelligente". Basta usare una funzione.

Detto questo, ho usato l'operatore di conversione implicito un paio di volte, e penso che possa essere utilizzato in un modo positivo alla rete.

Ad esempio, ho un piccolo linguaggio di programmazione su cui sto lavorando. Ha un oggetto per rappresentare un token Identifier nell'albero della sintassi, che è solo un wrapper per string per dargli un tipo concreto (come questo domanda recente chiesta). Quindi, invece di scrivere new Identifier("blah") o if(identifer == new Identifier("class")) ovunque, ho una conversione implicita da string a Identifier . Semplifica il codice mantenendo il comportamento chiaro.

Sì, crea un nuovo oggetto durante la conversione. Sì, mi richiede di assicurarmi che Identifier abbia uguaglianza di stile e sia sicuro che il mio design di classe non causerà problemi orribili. Ma è uno di quegli strumenti abbastanza pericolosi che puoi usare in alcune situazioni per rendere le cose molto più eleganti se sai cosa stai facendo.

Le sostituzioni esplicite delle conversioni non hanno riscontri positivi. Aggiungono verbosità al codice comunque, quindi è sempre meglio usare approcci più convenzionali.

    
risposta data 05.05.2015 - 16:59
fonte
3

L'operatore di casting è un operatore, e come tutti gli operatori non dovresti sovraccaricarlo a meno che tale sovraccarico preservi il significato accettato dell'operatore nell'ambiente in cui lavori. Uno dei motivi per cui Scala confonde tanta gente è che sono le librerie tendono a dirottare gli operatori per la creazione di DSL, rendendo molto difficile capire la libreria e scrivere codice che lo utilizza solo leggendo l'API. Non farlo.

Gli stessi operatori potrebbero avere significati accettati diversi in diverse lingue - ad es. << e >> di solito significano shift , ma in C ++ significano anche send-to / read-from stream . Il significato accettato può anche provenire dal dominio - ad esempio, molte librerie che trattano i percorsi preferiscono utilizzare l'operatore di divisione / per unire i percorsi - perché è ciò che viene utilizzato nella shell.

Ma l'operatore di cast ha lo stesso significato generale ovunque - quando lancio cast type X per digitare Y , sto dicendo "un Y è essenzialmente un X , solo ...". La parte dopo solo può fare un mondo di differenza - ma direi che qualsiasi sovraccarico di cast che non può essere tradotto in questo template è un abuso dell'operatore del caso.

  • (string) 10 - una stringa è essenzialmente un numero intero, rappresentato solo come testo.
  • (int) 5.4 - un int è essenzialmente un float, solo senza la frazione
  • (string) ['a', 'b', 'c'] - una stringa è essenzialmente un insieme di caratteri, solo concatenati tra loro.
  • (Rock) cat - un gatto è essenzialmente una roccia, solo ... beh ...

Non funziona nell'ultimo esempio - perché un gatto non è una roccia, non importa come lo metti. Stai avendo un comportamento strano perché quello che stai cercando di fare è strano. Solo perché sia il rock che il gatto hanno un'età non significa che un gatto sia essenzialmente una roccia con la stessa età - quel tipo di pensiero è peggio di Debole digitazione - non solo rompi l'astrazione che ti fornisce una strong digitazione che dice che 1069547520 è diverso da 1.5 anche se hanno la stessa rappresentazione nella memoria - stai creando un marchio nuove conversioni che non hanno senso né nel livello di astrazione elevato né nel livello di memoria insufficiente.

Quindi, alla tua domanda (" Qualcuno può dare un buon esempio ... ") - la risposta è no . Nessuno può dare un buon esempio, perché non ci sono buoni esempi. La trasmissione non ha senso quando X e Y non sono correlati, perché gli unici casi in cui un operatore di cast ha senso è quindi si può dire "una X è essenzialmente una Y, solo ...", e se si può dire questo - quello è la relazione tra X e Y.

    
risposta data 05.05.2015 - 18:30
fonte

Leggi altre domande sui tag