2010-01-23 14 views
6

tornare alle basi ...Come si può verificare le conversioni "sicure" tra i tipi di valore in .NET?

Per i tipi di riferimento, si può fare questo:

 SomeType someObject = firstObject as SomeType; 
     if (someObject == null) 
     { 
      // Handle the situation gracefully 
     } 
     else 
     { 
      // Do stuff 
     } 

Per i tipi di valore, la mia comprensione è che abbiamo le conversioni implicite (senza perdita di dati), le conversioni esplicite (necessario se c'è il rischio di perdita di dati), la classe Convert (un "wrapper di conversione" penso) e anche le conversioni specifiche del tipo (ad esempio double x = Double.Parse("2");), ma non ho trovato nulla di simile all'operatore as sopra.

Quindi, la mia domanda è: fa il quadro fornisce con qualche metodo/operatore/tecnica per fare qualcosa in questo senso:

 if (!Convert.CanConvert(someValue, someValueType)) 
     { 
      // Beware! Data loss can occur 
     } 
     else 
     { 
      // No data loss here 
     } 

In caso contrario, qualcuno là fuori può suggerire un approccio solido per costruire una di queste Metodo CanConvert?

Grazie mille!

EDIT (1): l'utente-caso/problema è il seguente: Dato un qualcosa approvata dal consumatore del codice (il mio altro sé, ma questo è irrilevante), (1) Verificare che qualcosa è un numero (abbastanza semplice) e (2) Posizionare qualcosa di nel tipo numerico "più piccolo" dove si adatta senza incorrere in perdita di dati.

Alcuni background: la natura di ciò che sto cercando di fare è più matematica che tecnica: sto cercando di vedere se/come posso adattare i tipi numerici esistenti in una sorta di gerarchia algebrica del modulo Monoid = > Gruppo => Anello => Campo (o una sua versione semplificata). Mentre si lavora su questo, e non molto sicuro di come, "una cosa tira l'altra" e mi sono trovato a dover fare i conti con le conversioni di tipo ...

+0

Ri: la tua modifica - Realmente faccio qualcosa del genere come parte di un algoritmo di compressione in linea. Il mio metodo? Inizia con un 'long', confrontalo con' byte.MaxValue', quindi 'short.MaxValue', e poi' int.MaxValue', e gettalo nel più piccolo che si adatta! – Aaronaught

+0

Sto provando qualcosa di molto simile a questo seguendo il suggerimento di Rob sotto. Stessa idea: prova le conversioni seguendo un ordine predefinito (considero tutto ciò che non è firmato "più piccolo" di qualsiasi cosa firmata per ragioni matematiche, anche se la memoria non è vera). BTW: hai qualche web/blog in cui posso controllare il tuo algoritmo? –

risposta

3

Come sul metodo TryParse sui vari tipi di valore?

int x; 

if (int.TryParse(someType.ToString(), out x)) 
    return x; 
+1

Hai bisogno di un ultimo paren di chiusura. – Lee

+0

+1 per offrire un approccio alla costruzione di uno di questi metodi. –

1

L'operatore as si basa sull'ereditarietà e i tipi di valore non ereditano. Probabilmente potresti scrivere un CanConvert() ma dovrebbe funzionare con i tipi di valore Boxed, e normalmente vuoi evitare la boxe.

Quindi, possibile: Sì, desiderabile: No.

Forse si può aggiungere uno scenario Usa-caso in cui si desidera utilizzare questo e allora possiamo raccomandare alternative.

Re: Edit (1)

Spero che siate consapevoli del fatto che il sistema di tipi numerici è per lo più bagaglio storico e non segue regole molto logici. Ad esempio non esiste un calcolo come short, vengono sempre convertiti in int prima di fare qualsiasi cosa.

Ma forse è possibile definire tale comportamento in termini di anello e campo, che Algebra è stata una "lunga volta che passa" per me.

+0

Oh sì, penso che chiunque abbia mai lavorato con i numeri nei computer è consapevole del fatto che non seguono regole molto logiche. Quindi qui sto costruendo il mio. Nella privacy della mia casa, ovviamente ... :-) –

1

Dai uno sguardo allo Convert.ChangeType. Potresti dirottarlo per raggiungere i tuoi scopi, anche se sarebbe lento a causa dell'eccezione del lancio e della conversione duplicata.

+0

Grazie - L'ho controllato prima di postare e sono d'accordo, non sembra perfetto per il mio scopo. –

+0

+1 per il suggerimento però. –

1

la parola chiave "as" è fondamentalmente un downcast sicuro. Poiché tutti i tipi di valore sono sigillati, non possono essere ereditati da.

Così il vostro codice sarebbe:

if (firstObject is MyValueType) 
{ 
    MyValueType obj = (MyValueType) firstObject; 
} 
else 
{ 
} 
1

Penso che si sta Incomprensione il punto della qualità di operatore. L'operatore as è approssimativamente equivalente al seguente codice:

if (firstObject is SomeType) 
    return (SomeType)firstObject; 
else 
    return null; 

Così come è più di un controllo di ereditarietà. (Come List implementa IList)

I tipi di valore non supportano l'ereditarietà, e per una buona ragione. Double e Int64 memorizzano entrambi il numero 1 in modi completamente diversi.

Fondamentalmente quello che vuoi è un metodo che determinerà per te se una conversione numerica è senza valore o no. Beh, io controbattere con "Perché?". Sebbene ci siano parecchi formati supportati dal CLR, le regole di conversione sono in genere piuttosto semplici. Ad esempio Int32 -> Double non ha perdite e qualsiasi conversione da "minore" a "più grande" è senza perdita, come SByte -> Int64.

Un'altra domanda è, cosa significherebbe un falso nel tuo esempio? Direi molto poco, ad esempio:

Convert.CanConvert(123456789.12345F, typeof(Byte)) 

A che serve il falso risultato? Supponiamo che si tratti di casi come Int32 -> Single, in cui alcuni dati andrebbero persi, ma in questo caso si perde una tonnellata di dati, poiché la rappresentazione "più vicina" dei byte è 255.

È a causa di questi due problemi che non esiste un tale metodo.

2

Henk è praticamente in the money. Vorrei aggiungere qualcosa alla sua risposta, se volessi:

La conversione del tipo di valore in .NET Framework funziona tramite l'interfaccia IConvertible. La classe Convert utilizza questo per quasi tutti i suoi metodi. Questo è molto diverso dagli operatori di conversione implicita/esplicita in C#, che sono semplicemente un'altra forma di zucchero sintattico.

Se si scrive questo:

public struct Duck 
{ 
    public static implicit operator Goose(Duck d) 
    { 
     ... 
    } 
} 

.NET Framework per sé non ha alcuna idea di che questo esiste. Viene emesso come op_implicit e tocca al linguaggio compilato per capire come usarlo. Non tutti i linguaggi MSIL attualmente li supportano. Quindi, questo codice funziona:

Goose g1 = duck; 

Questo codice non lo fa:

Goose g1 = (Goose)Convert.ChangeType(duck, typeof(Goose)); 

Al fine di implementare un metodo CanConvert che è a conoscenza di operatori di conversione implicito/esplicito, si sarebbe effettivamente necessario utilizzare la reflection per controlla i singoli metodi op_ e dovrei raccomandare di non farlo, in pratica non ne vedo il minimo uso.

+0

Cose interessanti. +1. –

Problemi correlati