c# vb.net casting directcast ctype

C#es equivalente a DirectCast de VB.NET?



casting ctype (9)

¿Realmente trataste de ejecutar tu código de muestra?

Respecto a...

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

... Usted postuló que se ejecutará. Tampoco funciona

¿Tiene C # un equivalente al DirectCast de VB.NET?

Soy consciente de que tiene () conversiones y la palabra clave ''como'', pero se alinean con CType y TryCast.

Para ser claros, estas palabras clave hacen lo siguiente;

CType / () arroja : si ya es el tipo correcto, ejecútelo; de lo contrario, busque un convertidor de tipo e inícielo. Si no se encuentra ningún convertidor de tipo, ejecute InvalidCastException.

Palabra clave TryCast / "as" : si es el tipo correcto, ejecútelo ; de lo contrario, devuelva nulo.

DirectCast : si es el tipo correcto, ejecútelo , de lo contrario lanzará una InvalidCastException.

Después de haber explicado lo anterior, algunas personas todavía respondieron que () es equivalente, por lo que me extenderé más sobre por qué esto no es cierto.

DirectCast solo permite reducir o ampliar las conversiones en el árbol de herencia. No admite conversiones en diferentes ramas como () hace, es decir:

C # - esto compila y ejecuta:

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

VB.NET - esto NO 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)

El equivalente en VB.NET a mi código C # es CType:

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


Creo que este escenario lo resume mejor por qué DirectCast tiene un sentido falso de seguridad de comprobación de tipos en tiempo de compilación para el tipo de no objeto (palabra clave del objeto), y está destinado a retroceder.

float f = 10; long l = f; Option Strict On Dim f As Single = 10 Dim l As Long = f

El codificador AC #, al descubrir que float no es asignable directamente a long y no compilará, hará esto:

long l = (long)f;

Cual es correcta.

Ahora, veamos nuestro codificador VB.NET, al descubrir que float no es asignable a long y no compilará, intentaremos esto:

Dim l As Long = DirectCast(f, Long)

Unos segundos después...

Programador de VB.Net: "Por favor, déjame hacer mi oferta, compila, por favor ... !!!"

Después de algunos momentos de navegación en Google y MSDN después:

Programador de VB.NET: "Ah ... así que tengo que usar esta construcción CLng o CType para las variables de conversión"

Dim l As Long = CLng(f)

Eso es lo que quise decir con DirectCast que tiene un sentido falso de seguridad de comprobación de tipos en tiempo de compilación. DirectCast está destinado a retroceder si un programador no sabe cuándo y dónde se deben utilizar. DirectCast es una manta de seguridad que no se usa todo el tiempo.

¿Qué tan útil es DirectCast en este escenario si no se usará después de todo?

[EDITAR]

@Jules

No pretendo que todos los programadores de VB.NET no sepan cuál es el uso real de DirectCast, algunos de ellos realmente saben que DirectCast solo está destinado a ser usado para tipos de objetos (y tipos primitivos que están encasillados en objetos) solamente .

Un escenario en el que un codificador VB.NET que recodifica el código existente C # para VB.NET llegará a una conclusión incorrecta, es con la simetría esperada (sea correcta o no) entre sí.

Cuando ve en el código esta construcción ...

TextBox txt = (TextBox)sender;

... Él traducirá eso a esto:

Dim txt As TextBox = DirectCast(sender, TextBox)

Cual es correcta.

Ahora, debido a que a los programadores nos encanta la simetría, algunos de nosotros (podría serlo también si no conozco CLng) tenderán a convertir este código ...

/* 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 esto:

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

Si una persona C # es la que convierte el código C # a VB.NET, se sentirá frustrado por la aparente falta de simetría aquí.

Pero para una persona de VB.NET encargada de convertir el código de C # a VB.NET, tendrá la impresión de que el compilador de C # no atrapa asignaciones de tipos incompatibles, mientras que VB.NET lo capta. Ahora, para ese aparente descubrimiento, alardearán de esa característica de VB.NET a sus colegas y algunos foros.

Pero no sea que el programador de VB.NET cometa el error de inferir erróneamente la intención del primer código. El fragmento de código de C # anterior comenzó su vida como este fue escrito inicialmente así:

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

Y eso no se compilará, el compilador de C # captura asignaciones de tipos incompatibles, del mismo modo que el VB.NET equivalente con Option Strict On tampoco compilará eso (aunque solo no se compilará cuando Option Strict esté configurado en On , demasiado indulgente). Entonces, necesitamos encasillar flotador a largo usando (long) . Se convierte en esto: long l = (long)f;

Ahora, para convertir un tipo de variable en otro tipo compatible, en la misma línea en que convertimos este código ...

TextBox txt = (TextBox)sender;

... a este código:

Dim txt As TextBox = DirectCast(sender, Textbox)

Debemos convertir este código ...

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

... a este código:

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

Pero, por desgracia, eso no se compilará, al fundir entre tipos primitivos compatibles, aquí es donde DirectCast se queda corto. No ofrece ninguna simetría al código C # anterior, no se puede usar para el fundido de tipos primitivos compatibles, a pesar de su nombre Direct Cast .

De la forma en que lo veo, DirectCast debería llamarse CastObject , ya que solo puede transmitir entre tipos de objetos (y también tipos primitivos que están encuadrados en el objeto) de todos modos. DirectCast realmente no tiene nada que ver con la asignación de tipos primitivos compatibles (entero, doble y su contraparte inferior y superior). Cuando se asigna entre tipos de primitivos compatibles, DirectCast deja de ser útil, especialmente lo hará retroceder de todos modos, y lo reemplazará con uno apropiado.

O a la inversa, la construcción de DirectCast debería modificarse para que pueda generar tipos compatibles, como lo hacen los lenguajes antiguos y nuevos, por ejemplo, C, C ++, C #, Java, Delphi, D, etc. Haciendo esto, lo hará ofrece una significativa simetría de VB.NET a otros idiomas cuando se trata de tipos de conversión. Al hacer esto, también podemos descartar (hipotéticamente solo, no podemos hacer que otros programas fallen que se basan en funciones antiguas) toda la plétora de funciones cuyos nombres no se mapean directamente a sus tipos (por ejemplo, CInt, CDbl, CSng, etc.), usará DirectCast en lugar de ellos.


Déjame intentar dar una oportunidad a esto.

Primero, déjenme ser claro en esto. Esto NO compilará

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

CType de VB

En VB, usarías:

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

En C #, usaría:

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

DirectCast de VB

Si es el tipo correcto, ejecútelo, de lo contrario lanzará una InvalidCastException.

El reparto directo solo puede subir o bajar por una rama, nunca por una diferente.

De esa explicación, sería un equivalente directo del elenco de C #. Sin embargo, en C # solo necesitarás especificar el operador de transmisión solo para echarlo. Casting up es totalmente opcional. Ejemplo:

// 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 # cast no busca ningún convertidor de tipo. Solo buscará cualquier sobrecarga de operador explícita / implícita definida para el tipo al que está intentando enviar.

TryCast de VB

Usted ya entendió correctamente que esto es equivalente a C # como palabra clave.


El () casting debería ser el mismo; arroja una InvalidCastException. Solo prueba esto en C #:

string t = "hello"; object x = t; int j = (int) x;


En realidad, el compilador solo detecta la violación de DirectCast si infiere que la variable tipada no se puede convertir al otro tipo

Estos son los equivalentes reales:

double d = 10; int i = (int)d; Dim d As Double = 10 Dim i As Integer = d

Tenga en cuenta la peligrosidad de esta construcción, cuando simplemente asigna doble a entero en VB.NET, el doble se reducirá accidentalmente a entero.

Mientras que los programadores de C # obtienen la seguridad en tiempo de compilación de la variable .NET que no se reduce accidentalmente. Los programadores de VB.NET tienen que lidiar con poner siempre DirectCast como un hábito de programación segura

Estos son los equivalentes reales:

// 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)

[EDITAR]

@ Dan Tao:

No es necesario utilizar DirectCast en C #, el tiempo de ejecución también evita la carga de valores largos a enteros. Esto es lo que afirma csauve, que C # no tiene DirectCast, que DirectCast puede evitar la asignación de diferentes tipos de variable, mientras que "porque" C # no tiene este DirectCast, se producirá un error silencioso al asignar diferentes tipos. Pero como puede ver, ese no es el caso, el lanzamiento de C # es exactamente el mismo que el DirectCast. Esto causará el error de tiempo de ejecución InvalidCastException :

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

Esto también causará el mismo error de tiempo de ejecución que el anterior:

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

Ahora, aquí es donde entra la parte "divertida", con VB.NET tienes que recordar muchas palabras clave para lograr algo. En C # si una determinada palabra clave se puede usar en otro escenario (como en esta versión de la variable) no inventarán otra palabra clave solo para que suceda.

En C # solo tienes que hacer esto:

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

En VB.NET, si realmente desea bajar la variable y desea la forma ortogonal de hacerlo, es decir, simplemente recordar una palabra clave, debe hacer esto:

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

Pero eso no se compilará, entonces, ¿cómo lograr un downcasting largo a entero? Debe recordar las otras palabras clave de VB.NET. Mientras que en C #, es ortogonal, la variable unbox que usa esta construcción (typehere) , también downcast / upcast usando la misma construcción (typehere) . En VB.NET hay una desconexión fundamental entre cargar un valor de un objeto y bajarlo. Entonces en VB.NET, tienes que hacer esto:

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

Hmm .. Creo que la confusión de Csta se debe al uso múltiple de C # (typehere) , primero se utiliza para downcasting; segundo, la misma construcción (verifique la primera parte de esta publicación, object o = l ) también se usa para desempaquetar el valor del objeto, que está seguro de que tiene el comportamiento de conversión de tipo seguro de DirectCast, ¡son lo mismo!

Este downcasting ...

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

... no es equivalente a:

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

Si quieres realizar downcasting, tienes que hacer esto:

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

Ahora, si un programador de VB.NET está programando por intención, y no tiene sueño mientras codifica, ¿por qué usará DirectCast cuando sabe que no puede asignar diferentes tipos? Si lo que el programador de VB.NET realmente quería es abatir, no debería intentar DirectCast en primer lugar. Ahora, el programador de VB.NET, al descubrir que DirectCast no se puede usar para downcasting, debe retroceder lo que escribió y reemplazarlo con CInt (o CType)


Parece claro que la funcionalidad que desea no está en C #. Prueba esto sin embargo ...

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; }

O, a pesar de que es diferente de la VB, llámalo así:

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


Tienes dos tipos de elenco en C #. Sin código adicional no hay equivalente a la palabra clave DirectCast en C #. Lo más cercano que tiene sin crearlo usted mismo es usar () .

Tienes:

My_Object c = (My_Object)object

y

My_Object c = object as My_Object

En el primero, si el lanzamiento falla, arroja un error. Usted está diciendo: "Sé lo que es este objeto, y si no lo es, hay algo mal".

En el segundo, a c se le asigna el valor nulo donde sea posible (nulo no se puede asignar a tipos de valores). En este, dices "Creo que sé lo que es este, pero si no, no arrojes un error, porque nada podría estar mal".

Otro casting de explicación posterior:

¿Cuál es la diferencia entre los moldes de tipo explícito e implícito?


Usted puede implementarlo usted mismo:

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

Utilizable de la siguiente manera:

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

Esto funciona y no involucra convertidores definidos por el usuario debido a que los genéricos se "resuelven" en tiempo de ejecución, pero las conversiones de tipo se resuelven en tiempo de compilación: el marco no genera implementaciones distintas para cada T sino que comparte la implementación para T similar, y por lo tanto el tiempo de ejecución no tiene la información para resolver las conversiones personalizadas.


SEGUNDA ACTUALIZACIÓN :

Bien, aquí hay un método de C # que se ha propuesto supuestamente hacer básicamente lo que hace DirectCast en 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; }

Aquí están los problemas con el método anterior:

  1. Tiene una restricción de where T : class , que DirectCast no tiene.
  2. DirectCast su argumento como un System.Object - de nuevo, no es cierto de DirectCast (al menos no que yo sepa).
  3. Se usa innecesariamente (por eso tiene la restricción de class en primer lugar); llamar (T) o arrojará una InvalidCastException si no funciona; ¿Por qué verificar si el valor coincide usando as , solo para arrojar la misma excepción que habría arrojado si hubieras tomado la ruta (T)o para empezar?

El método realmente podría reescribirse para proporcionar los mismos resultados que DirectCast siguiente manera:

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

Observación divertida: realmente todo lo que este método está haciendo es boxear un valor y luego intentar desempaquetarlo. En otras palabras, DirectCast<int>(12.0) sería realmente lo mismo que (int)(object)12.0 (y arrojaría una excepción). Al darse cuenta de esto, el método DirectCast<T> es bastante innecesario.

Ahora, aquí hay un ejemplo de cómo DirectCast y el casting con () son "diferentes" entre VB.NET y C #:

VB:

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

DO#:

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

OK, entonces uno compila, el otro no. Pero mira ese código. ¿Cuál es el objetivo de DirectCast cuando ya conoces el tipo de objeto? Esta no es una comparación realista, porque en VB.NET nunca habría ninguna razón para llamar a DirectCast como lo hace el código anterior. (Si desea convertir un valor conocido como del tipo System.Int32 en un valor de tipo System.Int64 en VB.NET, debería usar CLng , no DirectCast ). Si hubiera una variable escrita como System.Object en allí, entonces tendría sentido usar DirectCast , y el código siguiente sería de hecho equivalente:

VB:

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

DO#:

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

Así que mantengo DirectCast en VB.NET, en cualquier escenario en el que tenga sentido usarlo (es decir, cuando el tipo de un objeto no se conoce en tiempo de compilación), es lo mismo que un molde de estilo recto () en C # .

EDITAR : Bueno, lástima que haya publicado un código VB que no compiló. Después de reconsiderar lo que estaba diciendo, retiro mi segunda respuesta pero mantengo la primera.

Si te refieres al uso de DirectCast donde tomas un objeto de tipo desconocido e intentas convertirlo al tipo deseado, entonces es lo mismo que C # ''s () cast:

VB:

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

DO#:

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

Esto se debe a que, si o se escribe como un objeto del sistema, entonces la operación () en C # intentará desempaquetarlo. Esto fallará si los tipos no coinciden exactamente; por ejemplo, si o es un sistema en caja. System.Double , entonces (int)o arrojará una excepción porque o debe ser unboxed como un System.Double antes de que se pueda convertir a System.Int32 (si no me cree, ¡Pruébelo usted mismo!).

Nota: lo que sigue es inexacto porque DirectCast no realiza conversiones de ampliación; en cualquier caso, lo dejo para la posteridad.

Por otro lado, cuando se trata de conversiones de ampliación frente a restricción, usar la operación () en C # hace más trabajo que simplemente lanzar, como ha señalado (es decir, puede hacer (int)someDouble ). En este escenario, DirectCast es equivalente a la antigua asignación simple en C #:

VB:

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

DO#:

int i = 12; long l = i;