2010-01-23 7 views
6

Volver a lo básico ...¿Cómo se pueden verificar las conversiones "seguras" entre los tipos de valores en .NET?

Para los tipos de referencia, se puede hacer esto:

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

Para los tipos de valor, mi entendimiento es que tenemos las conversiones implícitas (sin pérdida de datos), las conversiones explícitas (es necesario si existe un riesgo de pérdida de datos), la clase Convert (un "contenedor de conversión", creo) y también conversiones específicas de tipo (por ejemplo, double x = Double.Parse("2");), pero no he encontrado nada similar al operador as anterior.

lo tanto, mi pregunta es: ¿Qué provee el marco con algún método/operador/técnica para hacer algo en este sentido:

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

Si no es así, ¿puede alguien por ahí sugerir un enfoque sólido para construir uno de esos CanConvert método?

¡Muchas gracias!

EDITAR (1): El usuario-caso/problema es el siguiente: dado un algo aprobada por el consumidor del código (mi otro yo, pero eso es irrelevante), (1) Compruebe que algo es un número (bastante fácil) y (2) Coloque algo en el tipo numérico "más pequeño" donde encaja sin incurrir en pérdida de datos.

Algunos antecedentes: la naturaleza de lo que estoy tratando de hacer es más matemática que técnica: estoy tratando de ver si puedo adaptar tipos numéricos existentes a una especie de jerarquía algebraica de la forma Monoid = > Grupo => Anillo => Campo (o una versión simplificada del mismo). Mientras trabajaba en esto, y no muy seguro de cómo, "una cosa llevó a la otra" y tuve que lidiar con las conversiones de tipo ...

+0

Re: tu edición - De hecho, hago algo así como parte de un algoritmo de compresión en línea. Mi método? Comience con un 'largo', compárelo con' byte.MaxValue', luego 'short.MaxValue', y luego' int.MaxValue', ¡y conéctelo al más pequeño que le quede! – Aaronaught

+0

Estoy intentando algo muy similar a esto siguiendo la sugerencia de Rob a continuación. La misma idea: intente las conversiones siguiendo un orden predefinido (considero cualquier cosa sin signo "más pequeña" que cualquier otra firmada por razones matemáticas, incluso si esto no es cierto en memoria). Por cierto: ¿tienes alguna web/blog donde pueda verificar tu algoritmo? –

Respuesta

3

¿Qué tal el método TryParse en los distintos tipos de valores?

int x; 

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

Sin embargo, necesita una última carta de clausura. – Lee

+0

+1 por ofrecer un enfoque para construir uno de esos métodos. –

1

El operador as se basa en la herencia y los tipos de valores no heredan. Probablemente podría escribir un CanConvert(), pero tendría que funcionar con los tipos de valores en caja, y normalmente quiere evitar el boxeo.

Por lo tanto, posible: Sí, Deseable: Nº

Tal vez se puede añadir un escenario de caso de uso en la que desea utilizar este y entonces podemos recomendar alternativas.

Re: Editar (1)

espero que son conscientes de que el sistema de tipos numéricos es sobre todo un bagaje histórico y no sigue unas reglas muy lógicas. No existe, por ejemplo, un cálculo short, siempre se convierten a int antes de hacer cualquier cosa.

Pero tal vez pueda definir ese comportamiento en términos de anillo y campo, que Algebra ha sido un "paso de tiempo largo" para mí.

+0

Oh, sí, creo que cualquiera que haya trabajado alguna vez con números en computadoras sabe que no siguen reglas muy lógicas. Así que aquí estoy construyendo el mío. En la privacidad de mi casa, por supuesto ... :-) –

1

Eche un vistazo a Convert.ChangeType. Podrías secuestrar eso para cumplir tus propósitos, aunque sería lento debido al lanzamiento de excepción y la conversión duplicada.

+0

Gracias - Lo revisé antes de publicarlo y estoy de acuerdo, no se ve muy bien para mi propósito. –

+0

+1 por la sugerencia sin embargo. –

1

la palabra clave "como" es básicamente un downcast seguro. Como todos los tipos de valores están sellados, no se pueden heredar.

lo que el código sería:

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

Creo que estás malinterpretando el punto del operador as. El operador as es más o menos equivalente al siguiente código:

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

Así que es más como un control de herencia. (Tal como List implementa IList)

Los tipos de valor no son compatibles con la herencia, y por una buena razón. Double e Int64 almacenan el número 1 de maneras completamente diferentes.

Básicamente lo que quiere es un método que determinará si la conversión de un número no tiene pérdidas o no. Bueno, yo respondo con "¿Por qué?". Si bien hay bastantes formatos compatibles con CLR, las reglas de conversión suelen ser bastante simples. Por ejemplo Int32 -> Double no tiene pérdida, y cualquier conversión de "más pequeña" a "más grande" no tiene pérdida, como SByte -> Int64.

Otra pregunta es, ¿qué significaría un falso en su ejemplo? Diría muy poco, por ejemplo:

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

¿De qué sirve el resultado falso? Usted implica que es para casos como Int32 -> Individual, donde se perderían algunos datos, pero en este caso se está perdiendo una tonelada de datos, ya que la representación Byte "más cercana" es 255.

Es por causa de estos dos cuestiones que no hay tal método.

2

Henk es prácticamente el dinero. Me gustaría agregar algo a su respuesta, si quisiera:

La conversión de valor en el marco .NET funciona con la interfaz IConvertible. La clase Convert hace uso de esto para casi todos sus métodos. Esto es muy diferente de los operadores de conversión implícita/explícita en C#, que no son más que otra forma de azúcar sintáctico.

Si se escribe esto:

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

El propio Marco .NET tiene ni idea de que esta existe. Se emite como op_implicit y depende del lenguaje compilado averiguar cómo usarlo. No todos los lenguajes MSIL en realidad los admiten. Por lo que este código funciona:

Goose g1 = duck; 

Este código no:

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

Con el fin de poner en práctica un método CanConvert que está al tanto de los operadores de conversión implícitos/explícitos, en realidad se tendría que utilizar la reflexión para verifique los métodos individuales de op_, y tendría que recomendar no hacerlo; en la práctica, puedo ver un escaso uso en la práctica.

+0

Cosas interesantes. +1. –

Cuestiones relacionadas