Domanda

C # ha un equivalente VB.NET DirectCast?

Sono consapevole che ha () cast e la parola chiave 'as', ma quelli si allineano a CType e TryCast.

Per essere chiari, queste parole chiave fanno quanto segue;

CType / () casts:Se è già il tipo corretto, lanciarlo, altrimenti cercare un convertitore di tipo e invocarlo.Se non viene trovato alcun convertitore di tipo, lanciare un InvalidCastException.

TryCast / parola chiave "come":Se è il tipo corretto, lanciarlo, altrimenti restituire null.

DirectCast:Se è il tipo corretto, lanciarlo, altrimenti lanciare un InvalidCastException.

Dopo aver spiegato quanto sopra, alcune persone hanno ancora risposto che () è equivalente, quindi espanderò ulteriormente il motivo per cui questo non è vero.

DirectCast consente solo di restringere o ampliare le conversioni sull'albero di ereditarietà.Non supporta le conversioni tra diversi rami come (), ad es.:

C# - questo compila ed esegue:

//This code uses a type converter to go across an inheritance tree
double d = 10;
int i = (int)d;

VB.NET -questo NON COMPILA

'Direct cast can only go up or down a branch, never across to a different one.
Dim d As Double = 10
Dim i As Integer = DirectCast(d, Integer)

L'equivalente in VB.NET per il mio codice c # è CType:

'This compiles and runs
Dim d As Double = 10
Dim i As Integer = CType(d, Integer)
È stato utile?

Soluzione

Sembra chiaro che la funzionalità desiderata non è in C #. Prova questo se ...

static T DirectCast<T>(object o, Type type) where T : class
{
    if (!(type.IsInstanceOfType(o)))
    {
        throw new ArgumentException();
    }
    T value = o as T;
    if (value == null && o != null)
    {
        throw new InvalidCastException();
    }
    return value;
}

In alternativa, anche se è diverso dal VB, chiamatelo come:

static T DirectCast<T>(object o) where T : class
{
    T value = o as T;
    if (value == null && o != null)
    {
        throw new InvalidCastException();
    }
    return value;
}

Altri suggerimenti

SECONDO AGGIORNAMENTO:

OK, ecco un metodo C# che è stato proposto per presumibilmente fare fondamentalmente cosa DirectCast fa in VB.NET.

static T DirectCast<T>(object o) where T : class
{
    T value = o as T;
    if (value == null && o != null)
    {
        throw new InvalidCastException();
    }
    return value;
}

Ecco i problemi con il metodo sopra:

  1. Ha un where T : class vincolo, che DirectCast non lo fa.
  2. Inscatola il suo argomento come un System.Object -- ancora una volta, non è vero di DirectCast (almeno non che io sappia).
  3. Utilizza as inutilmente (che è il motivo per cui ha il class vincolo in primo luogo);chiamata (T) o getterà un InvalidCastException se non funziona;perché controllare se il valore corrisponde usando as, solo per lanciare la stessa eccezione che sarebbe stata lanciata se fosse andato il (T)o percorso per cominciare?

Il metodo potrebbe davvero essere riscritto per fornire gli stessi risultati di DirectCast come segue:

static T DirectCast<T>(object o) {
    return (T)o;
}

Osservazione divertente:in realtà tutto questo metodo sta facendo è inscatolare un valore e quindi tentare di annullarlo.In altre parole, DirectCast<int>(12.0) sarebbe davvero lo stesso di (int)(object)12.0 (e uno farebbe un'eccezione).Rendendosi conto di ciò, la proposta DirectCast<T> metodo abbastanza inutile del tutto.

Ora, ecco un esempio di come DirectCast e casting con () sono "diversi" tra VB.NET e C#:

VB:

Dim i As Integer = 12
Dim l As Long = DirectCast(i, Long) ' does not compile '

C#:

int i = 12;
long l = i; // DOES compile

OK, quindi uno compila, l'altro no.Ma guarda quel codice. Che senso ha DirectCast quando conosci già il tipo di un oggetto? Questo non è un confronto realistico, perché in VB.NET non ci sarebbe mai alcun motivo per chiamare DirectCast come fa il codice sopra.(Se si desidera convertire un valore noto per essere di tipo System.Int32 ad un valore di tipo System.Int64 in VB.NET, useresti CLng, non DirectCast.) Se ci fosse una variabile digitata come System.Object là dentro, poi avrebbe senso usare DirectCast, e il codice sotto sarebbe effettivamente equivalente:

VB:

Dim i As Integer = 12
Dim o As Object = i
Dim l As Long = DirectCast(o, Long) ' compiles, throws an exception '

C#:

int i = 12;
object o = i;
long l = (long)o; // compiles, throws an exception

Quindi lo sostengo DirectCast in VB.NET, in qualsiasi scenario in cui effettivamente ha senso usarlo (cioè, quando il tipo di un oggetto non è noto in fase di compilazione), è lo stesso di una scala ()- stile cast in C#.


MODIFICARE:Beh, vergogna su di me per la pubblicazione di un codice VB che non ha compilato.Dopo aver riconsiderato quello che stavo dicendo, ritiro il mio secondo rispondi ma mantieni il primo.

Se ti riferisci all'uso di DirectCast dove si prende un oggetto di tipo sconosciuto e si tenta di lanciarlo al tipo desiderato, allora essere lo stesso di c # ' s () cast:

VB:

Dim o As Object = SomeObject()
Dim i As Integer = DirectCast(o, Integer)

C#:

object o = SomeObject();
int i = (int)o;

Questo perché, se o viene digitato come un System.Object, poi il () l'operazione in c # tenterà di annullarla.Questo fallirà se i tipi non corrispondono esattamente;ad esempio, se o è un boxed System.Double, poi (int)o farà un'eccezione perché o dovere essere unboxed come un System.Double prima che possa essere convertito in un System.Int32 (se non mi credi, provalo tu stesso!).


Nota:il seguente è impreciso perché DirectCast fare non eseguire conversioni di ampliamento;in ogni caso, lo lascio ai posteri.

D'altra parte, quando si tratta di ampliamento vs.restringere le conversioni, usando il () l'operazione in c# fa più lavoro del semplice casting, come hai sottolineato (cioè, puoi fare (int)someDouble).In questo scenario, DirectCast è equivalente alla semplice vecchia assegnazione in C#:

VB:

Dim i As Integer = 12
Dim l As Long = DirectCast(i, Long) ' does not compile, actually '

C#:

int i = 12;
long l = i;

È possibile implementare da soli:

static T CastTo<T>(this object obj) { return (T)obj; }

Utilizzabile come segue:

3.5.CastTo<int>(); //throws InvalidCastException.

funziona e non comporta convertitori definiti dall'utente a causa del fatto che i generici sono "risolti" in fase di esecuzione, ma le conversioni di tipo sono risolti al momento della compilazione - il quadro in realtà non genera implementazioni distinte per ciascun T bensì azioni di attuazione per T simili, e quindi il tempo di esecuzione non ha le informazioni per risolvere i conversioni personalizzate.

In realtà il compilatore solo cattura la violazione DirectCast se ne deduce che la variabile tipizzata non può essere convertito in un altro tipo

Questi sono gli equivalenti attuali:

double d = 10;
int i = (int)d;

Dim d As Double = 10
Dim i As Integer = d

Si noti la pericolosità di questo costrutto, quando basta semplicemente assegnare il doppio per intero in VB.NET, il doppio sarà accidentalmente ridimensionato per intero.

considerando che i programmatori C # ottenere la sicurezza in fase di compilazione di non downsizing accidentalmente .NET variabile. programmatori VB.NET devono fare i conti con la messa sempre DirectCast come abitudine di programmazione sicura

Questi sono gli equivalenti attuali:

// will not compile, cannot convert double to int

double d = 10;
int i = d; 

' will not compile, cannot convert double to int

Dim d As Double = 10
Dim i As Integer = DirectCast(d, Integer) 

[EDIT]

@ Dan Tao:

Non c'è alcun bisogno di usare DirectCast in C #, il runtime impedisce anche il caricamento di tempo per valore intero. Questo è ciò che sta sostenendo csauve, che C # non hanno DirectCast, che DirectCast può impedire l'assegnazione di diversi tipi di variabili, mentre "perché" C # non ha questo DirectCast, sarà silenziosamente errore sull'assegnazione di tipi diversi. Ma come si può vedere, non è questo il caso, getto C # s 'è esattamente la stessa DirectCast. Questo farà sì che InvalidCastException errore di runtime:

long l = 10;
object o = l;
int i = (int)o;

Questo causerà anche lo stesso Errore di runtime come sopra:

Dim l As Long = 10
Dim o As Object = l
Dim i As Integer = DirectCast(o, Integer)

Ora, questo è dove la parte "divertimento" entra, con VB.NET si deve ricordare molte parole chiave, al fine di realizzare qualcosa. In C #, se una determinata parola chiave potrebbe essere utilizzato in un altro scenario (come in questo downcasting di variabile) non inventeranno un'altra parola chiave solo per realizzarlo.

In C # non resta che fare questo:

long l = 10;
object o = l;
int i = (int)(long)o;

In VB.NET, se si vuole veramente downcast variabile, e desidera che il modo ortogonale di farlo, vale a dire solo ricordare una parola chiave, è necessario farlo:

 Dim l As Long = 10
 Dim o As Object = l
 Dim i As Integer = DirectCast(DirectCast(o, Long), Integer)

Ma non compilerà, così come ottenere downcasting lungo per intero? È necessario ricordare altre parole chiave di VB.NET. Mentre in C #, è ortogonale, è variabile Unbox utilizzare questo costrutto (typehere), è anche abbattuto / upcast utilizzando lo stesso (typehere) costrutto. In VB.NET c'è una sconnessione fondamentale fra il caricamento di un valore da oggetto e downcasting esso. Quindi, in VB.NET, devi fare questo:

 Dim l As Long = 10
 Dim o As Object = l
 Dim i As Integer = CType(o, Integer)

Hmm .. Credo che la confusione csauve deriva da C # uso multiplo di (typehere), prima viene utilizzato per downcasting; secondo, lo stesso costrutto (controllare la prima parte di questo post, object o = l) è utilizzato anche per spacchettamento del valore dell'oggetto, che certi è sicuro comportamento di tipo conversione di DirectCast, sono uguali!

Questa downcasting ...

long l = 1;
int i = (int) l;

... non è equivalente a:

Dim l As Long = 1
Dim i As Integer = DirectCast(l, Integer)

Se si desidera eseguire downcasting, devi fare questo:

Dim l As Long = 1
Dim i As Integer = CInt(l) ' can also use CType

Ora, se un programmatore VB.NET sta programmando da intenti, e non sonno durante la codifica, perché userà DirectCast quando egli è pienamente consapevole del fatto che esso non può assegnare i tipi differenti? Se ciò che il programmatore VB.NET voleva davvero è abbattuta, non dovrebbe tentato DirectCast in primo luogo. Ora il programmatore VB.NET, dopo aver scoperto che DirectCast non può essere utilizzato per downcasting, deve tornare indietro ciò che ha scritto e sostituirlo con CInt (o CType)

VB.NET:

Dim xxx as label = Directcast(sender, label)

C #:

label xxx = (label)sender;

Hai davvero tenta di eseguire il codice di esempio?

Per quanto riguarda ...

//This code uses a type converter to go across an inheritance tree
string s = "10";
int i = (int)s;

... È postulato che verrà eseguito. Inoltre non funziona

Vorrei cercare di dare un colpo a questo.

In primo luogo, mi permetta di essere chiaro su questo. Questo non di compilazione:

//This code uses a type converter to go across an inheritance tree
string s = "10";
int i = (int)s;

VB CType

In VB, si userebbe:

Dim s as String = "10"
Dim i as Integer = CType(s, Integer)

In C #, vorrei utilizzare:

string s = "10";
int i = Convert.ToInt32(s);

VB DirectCast

  

Se è il tipo corretto, gettò,   un altrimenti tiro   InvalidCastException.

     

Cast diretta può solo salire o scendere una   ramo, non attraverso una diversa   uno.

Da questa spiegazione, sarebbe un equivalente diretto del C # cast. Tuttavia in C # si avrebbe solo bisogno di specificare l'operatore di cast solo per abbassando. Casting up è del tutto facoltativa. Esempio:

// casting down
object t = "some random string needing to be casted down";
string s = (string) t;
// casting up
object a = s;
// explicitly casting up although it's totally optional
object b = (object) s;

C # fusione non sembra per qualsiasi tipo Converter. Si farà il punto solo per qualsiasi sovraccarico definito esplicita / implicita operatore per il tipo si sta cercando di cast.


VB TryCast

È già capito giustamente che questo equivale a C # come parola chiave.

Credo che questo scenario le somme che la cosa migliore per questo DirectCast ha senso falso di tipo in fase di compilazione il controllo di sicurezza per i non-oggetto (oggetto parola chiave) il tipo, ed è solo destinata ad essere precedentemente ricoperti.

float f = 10;
long l = f;

Option Strict On    
Dim f As Single = 10
Dim l As Long = f

A C # coder, dopo aver scoperto che il galleggiante non direttamente imputabili a lungo e non si compila, lo farà:

long l = (long)f;

che è corretto.

Ora, torniamo al nostro coder VB.NET, dopo aver scoperto che il galleggiante non è assegnabile a lungo e non si compila, cercherà in questo modo:

Dim l As Long = DirectCast(f, Long)

Dopo alcuni secondi ...

VB.Net programmatore: "Per favore, mi permetta di fare la mia offerta, si prega di compilare, per favore ... !!!"

Dopo qualche usare Google-fu e MSDN-browsing istanti dopo:

VB.NET programmatore: "Ah .. quindi devo usare questo costrutto CLng o CType per la fusione variabili"

Dim l As Long = CLng(f)

Questo è ciò che intende per DirectCast ha falso senso di sicurezza in fase di compilazione controllo di tipo. DirectCast sono solo destinata ad essere precedentemente ricoperti se un programmatore non sa quando e dove dovrebbero essere utilizzati. DirectCast è una coperta di sicurezza che è non indossato per tutto il tempo.

Come utile DirectCast è in questo scenario, se non verrà utilizzato, dopo tutto?


[EDIT]

@Jules

Non ho la pretesa che tutti i programmatori VB.NET non sanno che cosa è il vero uso di DirectCast, alcuni dei quali davvero sanno che DirectCast sono solo pensato per essere utilizzato per i tipi di oggetto (e tipi primitivi che vengono mostrate all'interno di oggetto) solo.

Uno scenario in cui un VB.NET coder ricodifica C codice esistente # a VB.NET uno arriverà a conclusione sbagliata, è con previsto (sia esso a ragione o no) lingue simmetria tra loro.

Quando vede nel codice questo costrutto ...

TextBox txt = (TextBox)sender;

... Egli si tradurrà che a questo:

Dim txt As TextBox = DirectCast(sender, TextBox)

che è corretto.

Ora, Perché noi programmatori amore simmetria, alcuni di noi (io potrebbe essere troppo se non so CLng) tenderà a convertire questo codice ...

/* numbers are stored in file as float(component's file structure 
is designed by 3rd party company) */
float f = file.ReadFloat(0); 
long l = (long)f; // but we don't care about using the fractional part

... a questo:

Dim f As Single = file.ReadFloat(0)
Dim l As Long = DirectCast(f, Long)

Se un C # persona è quella convertire codice C # a VB.NET, sarà frustrato per la apparente mancanza di simmetria qui.

Ma per una persona VB.NET compito di convertire codice C # a VB.NET, otterrà l'impressione che il C # compilatore non coglie le assegnazioni di tipo incompatibili, mentre VB.NET afferra. Ora, per quella scoperta apparente, sarà vantarsi quella caratteristica VB.NET ai suoi colleghi e alcuni forum.

Ma per non essere il programmatore VB.NET commette l'errore di inferire a torto l'intento del primo codice. Il C # s 'frammento di codice sopra ha iniziato la sua vita come questo è stato inizialmente scritto in questo modo:

float f = file.ReadFloat(0); 
long l = f; 

E che non compilazione, compilatore C # catture le assegnazioni di tipo incompatibili, nella stessa vena che il VB.NET equivalente con Option Strict On inoltre non compilare che (anche se solo non si compila quando Option Strict è insieme a On, troppo indulgente). Quindi abbiamo bisogno di typecast galleggiante usando lunga (long). Diventa questo: long l = (long)f;

Ora, per lanciare un tipo di variabile ad un altro tipo compatibile, nella stessa vena che si convertono questo codice ...

TextBox txt = (TextBox)sender;

... a questo codice:

Dim txt As TextBox = DirectCast(sender, Textbox)

Dobbiamo convertire questo codice ...

long l = (long)f; // will compile

... a questo codice:

Dim l As Long = DirectCast(f, Long) ' will not compile

Ma, ahimè, che non si compila, sulla fusione tra i tipi primitivi compatibili, questo è dove DirectCast abbatte breve. Non offre alcuna simmetria per il codice C # di cui sopra, non può essere utilizzato su fusione tipi primitivi compatibili, nonostante il suo nome diretto Cast .

Il mio modo di vedere, DirectCast deve essere denominato CastObject , dal momento che può lanciare solo tra tipi di oggetti (e anche tipi primitivi che sono boxed in oggetto) in ogni caso. DirectCast davvero non ha commercio con l'assegnazione di tipi primitivi compatibili (integehm, doppio, e la loro controparte inferiore e superiore). Durante l'assegnazione tra i tipi primitivi compatibili, DirectCast cessa di essere utile, in particolare si è comunque tornare indietro, e sostituirlo con una corretta uno.

O l'altro mio modo di vedere, costrutto DirectCast deve essere modificata in modo da poter lanciare tipi compatibili come il modo in cui vecchi e nuovi linguaggi fanno da allora, ad esempio, C, C ++, C #, Java, Delphi, D, ecc In questo modo, che offrirà VB.NET notevole simmetria ad altre lingue, quando si tratta di digitare casting. In questo modo, si può anche buttare via (ipoteticamente solo, non possiamo fare altri programmi non riescono che si basano su vecchie funzioni) tutte pletora di funzioni che i nomi non Mappe direttamente ai suoi tipi (ad esempio CInt, CDbl, CSng, ecc), abbiamo sarà solo utilizzare DirectCast in luogo di essi.

Si hanno due tipi di getto in C #. Senza codice aggiuntivo non esiste un equivalente alla parola DirectCast in C #. Il più vicino si dispone senza creare da soli è quello di utilizzare ().

Hai:

My_Object c = (My_Object)object

e

My_Object c = object as My_Object

Nella prima, se il cast non riesce, si genera un errore. State dicendo, "Io so cosa questo oggetto è, e se non lo è, c'è qualcosa di sbagliato".

Nel secondo, c viene assegnato il valore nullo ove possibile (null non può essere assegnato a tipi di valore). In questo che stai dicendo "Credo di sapere che cosa questo è, ma se non non getto un errore, perché nulla potrebbe essere sbagliato".

Altri post che spiega casting:

Qual è la differenza tra esplicita e tipo cast impliciti?

DirectCast e () non sempre generano lo stesso IL, quindi penso che questa è una differenza tra la VB e C # compilatori.

AFAICT, tipi di riferimento vengono espressi usando l'castclass istruzioni IL, mentre per i tipi di valore il compilatore genera l'IL pertinenti a seconda dei tipi di ingresso.

In C #, gettando da double al integer emette l'istruzione IL conv.i4, che allegramente sovrascrivere il bit del segno o qualsiasi altra cosa in uscita, se il valore è troppo grande. In VB, si tratta di un errore di compilazione.

È interessante notare che, se si utilizza una variabile object intermedio per contenere il doppio, quindi il cast avrà esito negativo sia per C # e VB ... ma in fase di esecuzione. Entrambi i compilatori emettono un'istruzione unbox invece di cercare di fare una conversione.

The () casting should be the same; it throws an InvalidCastException. Just try this in C#:

 string t = "hello";
 object x = t;
 int j = (int) x;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top