2010-09-28 17 views

risposta

9

Convenienza?

Più o meno, sì. Considera il caso in cui hai un oggetto simile al numero (ad esempio, uno Complex) su cui esegui i calcoli. Chiaramente, scrivere un codice come:

Complex result = c1 * new Complex(2) + new Complex(32); 

è molto fastidioso e difficile da leggere. Le conversioni implicite aiutano qui (un'alternativa sarebbe il sovraccarico dell'operatore in questo esempio, ma ciò porterebbe a molti sovraccarichi simili).

Esiste una linea guida per questo?

Fornire il minor numero possibile di conversioni implicite, poiché potrebbero nascondere problemi. La conversione implicita riduce la chiarezza dello stesso importo con il quale aumenta la tersezza. A volte questo è buono, ma a volte no.

Trovo meglio per limitare le conversioni implicite di tipi molto simili, come ad esempio gli oggetti numero-come nel mio esempio di cui sopra: un int essenzialmente is-a Complex (dal punto di vista matematico, anche se non è modellata via eredità), quindi una conversione implicita ha un senso.

In VB, una conversione implicita viene chiamato “Widening” (al contrario di Narrowing, che è explicit) e questo descrive bene: nessuna informazione viene persa nel corso della conversione.

Inoltre, un operatore è essenzialmente una funzione builder e presenta (alcuni dei) vantaggi usuali di una funzione builder su un costruttore: vale a dire, può riutilizzare i valori memorizzati nella cache invece di creare sempre nuove istanze.

Considerare il mio esempio Complex. Si consiglia di memorizzare nella cache i valori per i numeri complessi utilizzati più spesso:

Class Complex { 
    // Rest of implementation. 

    private static Complex[] cache = new[] { 
     new Complex(-1), new Complex(0), new Complex(1) }; 

    public implicit operator Complex(int value) { 
     if (value >= -1 && value <= 1) 
      return cache[value]; 
     else 
      return new Complex(value); 
    } 
} 

Naturalmente, se questo micro-ottimizzazione è efficace è un'altra questione.

+0

Grazie, come lo faresti per i sovraccarichi dell'operatore che potrebbero aiutare il tipo Complesso? Devi essere in grado di modificare il tipo int, giusto? –

+0

@Joan: No, dal momento che è possibile implementare gli operatori in entrambe le direzioni: * dal * tipo personalizzato e * al * tipo personalizzato. Nel mio esempio, semplicemente 'Complex' implementa un operatore implicito Operatore' 'Compl (valore int)'. –

+0

Grazie ho capito ora. –

3

L'uso di conversioni implicite/esplicite è un problema di convenienza e uno che molte linee guida di programmazione suggeriscono di evitare a favore dei metodi espliciti ConvertToXXX.

Uno dei problemi è che l'uso di conversioni implicite/esplicite sovraccarica ulteriormente le funzioni dell'operatore di casting.Si dà il duplice scopo di

  • Visualizzazione dello stesso oggetto attraverso un diverso tipo/interfaccia nella gerarchia dell'oggetto
  • Coverting l'oggetto a un nuovo tipo del tutto

Purtroppo C# fa già il secondo in altre aree (con primitive e boxe).

1

Personalmente, io uso le conversioni quando so che le RHS possono essere convertite in un membro statico di una classe (come dire color = "red" implicare color = Colors.Red)

Io uso il nuovo operatore quando ho intenzione di creare effettivamente un nuova istanza.

2

Se due classi devono essere convertibili l'una con l'altra, ma non condividono un'interfaccia di una classe base che consente questo comportamento automaticamente, si useranno le conversioni. Le conversioni implicite dovrebbero mai avere una possibilità di perdita di dati; sono spesso considerate conversioni "allarganti". Ad esempio, la conversione di un in un long è una conversione allargata e non vi è alcun problema inerente alla conversione implicita. Le conversioni esplicite possono comportare la possibilità di perdita di dati; a long può o non può essere convertibile in un int, a seconda del suo valore.

Un trucco che ho usato con le conversioni implicite è quello di convertire le classi in spazi dei nomi diversi l'una con l'altra quando non avevo un'altra opzione ragionevole. Ad esempio, un servizio WCF restituisce un oggetto AuthenticationToken che devo passare a un servizio WCF in un diverso spazio dei nomi. Entrambi hanno questo oggetto AuthenticationToken, e la conversione costante sarebbe stata un dolore. La mia soluzione implicava l'utilizzo di public static implicit operator in una classe parziale per aggiungere la funzionalità per convertire ogni modo.

+0

L'idea che "la conversione implicita non dovrebbe causare perdita di dati" è un linguaggio popolare, ma penso che una migliore idea sarebbe "* le conversioni implicite di andata e ritorno non dovrebbero causare la perdita di dati". Se un 'SimpleType' rappresenta un' ComplicatedType' dove le proprietà "complicate" corrispondono tutti ai valori predefiniti, l'ampliamento delle conversioni dovrebbe essere consentito solo da 'SimpleType' a' ComplicatedType', ma se rappresenta un 'ComplicatedType' dove i valori delle proprietà complicate sono sconosciuti la conversione implicita dovrebbe, se possibile, essere consentita solo nell'altro modo. – supercat

5

Uno dei motivi per cui l'utilizzo della conversione implicita con tipi semplici come XName è, credo, la convenienza nel chiamare i metodi.

Ad esempio, è possibile scrivere

var info = root.Elements ("user").Element ("info").Value; 

Semplicità a estrazione di dati è quello che LINQ è tutto, e se abbiamo dovuto scrivere

var info = root.Elements (new XName ("user")).Element (new XName ("info")).Value; 

anche per le query più semplici, sarebbe LINQ essere totalmente ne vale la pena per quelli complessi?

Un altro problema importante qui è che gli XNames sono atomizzati. Vedere MSDN:

Gli oggetti XName sono garantiti per essere atomizzati; ovvero, se due oggetti XName hanno esattamente lo stesso spazio dei nomi e esattamente lo stesso nome locale, condivideranno la stessa istanza. Anche gli operatori di uguaglianza e confronto sono forniti esplicitamente per questo scopo.

Tra gli altri vantaggi, questa funzione consente un'esecuzione più rapida delle query. Quando si effettua il filtraggio sul nome di elementi o attributi, i confronti espressi nei predicati utilizzano il confronto dell'identità, non il confronto dei valori. È molto più veloce determinare che due riferimenti si riferiscono effettivamente allo stesso oggetto piuttosto che confrontare due stringhe.

Non è possibile fornire atomizzazione nel costruttore, ma definire una conversione permette di scegliere oggetto corrispondente dalla piscina e restituirlo come se fosse una nuova istanza.

Problemi correlati