2010-05-19 20 views
6

Estoy tratando de descubrir la sintaxis que admite unboxing un tipo integral (corto/int/largo) a su tipo intrínseco, cuando el tipo en sí es desconocido.Desempaquetar en un tipo desconocido

Aquí está un ejemplo completamente artificial que demuestra el concepto:

// Just a simple container that returns values as objects 
struct DataStruct 
{ 
    public short ShortVale; 
    public int IntValue; 
    public long LongValue; 
    public object GetBoxedShortValue() { return ShortVale; } 
    public object GetBoxedIntValue() { return IntValue; } 
    public object GetBoxedLongValue() { return LongValue; } 
} 

static void Main(string[] args) 
{ 

    DataStruct data; 

    // Initialize data - any value will do 
    data.LongValue = data.IntValue = data.ShortVale = 42; 

    DataStruct newData; 

    // This works if you know the type you are expecting! 
    newData.ShortVale = (short)data.GetBoxedShortValue(); 
    newData.IntValue = (int)data.GetBoxedIntValue(); 
    newData.LongValue = (long)data.GetBoxedLongValue(); 

    // But what about when you don't know? 
    newData.ShortVale = data.GetBoxedShortValue(); // error 
    newData.IntValue = data.GetBoxedIntValue(); // error 
    newData.LongValue = data.GetBoxedLongValue(); // error 
} 

En cada caso, los tipos integrales son consistentes, por lo que debería haber alguna forma de sintaxis que dice "el objeto contiene un tipo simple de X, devuelve eso como X (aunque no sé qué es X) ". Debido a que los objetos en última instancia provienen de la misma fuente, realmente no puede haber un desajuste (¡corto! = Largo).

Pido disculpas por el ejemplo inventado, me pareció la mejor manera de demostrar la sintaxis.

Gracias.

+0

Todos los métodos 'GetBoxed' devuelven' LongValue'. ¿Error de tipografía? – unholysampler

+0

¿Qué quiere decir "no puede haber un desajuste"? Si conoce el tipo, entonces no puede haber; si no lo haces, entonces puede haberlo. –

+1

¿Cómo le gustaría usar el resultado de su desempaquetado? Si no sabes el tipo después de unboxing, entonces no puedes hacer nada con él (aparte de adivinar y usar 'dynamic'). Si conoces el tipo después del desempaquetado, entonces desmarca de ese tipo. En su ejemplo, usted sabe que a newData.IntValue solo se le puede asignar un int, por lo que _have_ que hacer 'newData.IntValue = (int) yourUnknownBoxedValue;'. Si esto falla, no puede asignarlo a newData.IntValue. Si no falla, entonces estás bien. Entonces, lo que estoy diciendo es realmente: deberías pensar en un ejemplo no artificial, porque esto no tiene sentido. – Joren

Respuesta

2

Bueno, el object en sí mismo es el tipo más genérico que conoce el framework. Si es un tipo de valor encuadrado (incluida la primitiva) u otra cosa no importa; si quiere ser más específico, tiene para hacer una conversión a menos que permanezca en el mundo "vagamente tipado" con object (o, en C# 4, dynamic).

Nótese, sin embargo, que se puede utilizar una lista de condiciones para lograr lo que quiere:

object boxedValue = GetBoxedValue(); 
if (typeof(short) == boxedValue.GetType()) { 
    newData.ShortValue = (short)boxedValue; 
} else if (typeof(int) == boxedValue.GetType()) { 
    newData.IntValue = (int)boxedValue; 
} else if (typeof(long) == boxedValue.GetType()) { 
    newData.LongValue = (long)boxedValue; 
} else { 
    // not one of those 
} 

Editar: Una "caja" genérico también puede hacer lo que quiera:

public class Box<T>: IConvertible where T: struct, IConvertible { 
    public static implicit operator T(Box<T> boxed) { 
     return boxed.Value; 
    } 

    public static explicit operator Box<T>(T value) { 
     return new Box<T>(value); 
    } 

    private readonly T value; 

    public Box(T value) { 
     this.value = value; 
    } 

    public T Value { 
     get { 
      return value; 
     } 
    } 

    public override bool Equals(object obj) { 
     Box<T> boxed = obj as Box<T>; 
     if (boxed != null) { 
      return value.Equals(boxed.Value); 
     } 
     return value.Equals(obj); 
    } 

    public override int GetHashCode() { 
     return value.GetHashCode(); 
    } 

    public override string ToString() { 
     return value.ToString(); 
    } 

    bool IConvertible.ToBoolean(IFormatProvider provider) { 
     return value.ToBoolean(provider); 
    } 

    char IConvertible.ToChar(IFormatProvider provider) { 
     return value.ToChar(provider); 
    } 

    sbyte IConvertible.ToSByte(IFormatProvider provider) { 
     return value.ToSByte(provider); 
    } 

    byte IConvertible.ToByte(IFormatProvider provider) { 
     return value.ToByte(provider); 
    } 

    short IConvertible.ToInt16(IFormatProvider provider) { 
     return value.ToInt16(provider); 
    } 

    ushort IConvertible.ToUInt16(IFormatProvider provider) { 
     return value.ToUInt16(provider); 
    } 

    int IConvertible.ToInt32(IFormatProvider provider) { 
     return value.ToInt32(provider); 
    } 

    uint IConvertible.ToUInt32(IFormatProvider provider) { 
     return value.ToUInt32(provider); 
    } 

    long IConvertible.ToInt64(IFormatProvider provider) { 
     return value.ToInt64(provider); 
    } 

    ulong IConvertible.ToUInt64(IFormatProvider provider) { 
     return value.ToUInt64(provider); 
    } 

    float IConvertible.ToSingle(IFormatProvider provider) { 
     return value.ToSingle(provider); 
    } 

    double IConvertible.ToDouble(IFormatProvider provider) { 
     return value.ToDouble(provider); 
    } 

    decimal IConvertible.ToDecimal(IFormatProvider provider) { 
     return value.ToDecimal(provider); 
    } 

    DateTime IConvertible.ToDateTime(IFormatProvider provider) { 
     return value.ToDateTime(provider); 
    } 

    string IConvertible.ToString(IFormatProvider provider) { 
     return value.ToString(provider); 
    } 

    object IConvertible.ToType(Type conversionType, IFormatProvider provider) { 
     return value.ToType(conversionType, provider); 
    } 
} 

Esto se puede usar en lugar de object; sigue siendo una referencia de objeto, pero también está fuertemente tipada a la estructura original o tipo primitivo.

+0

Como nota al margen, el Framework ya contiene una clase notablemente similar a 'Box ' (aunque sin los operadores de conversión y IConvertible): 'StrongBox ' (System.Runtime.CompilerServices). – Ruben

1

Puede devolver dynamic, que luego se puede convertir a un tipo integral.

2

No estoy completamente seguro de lo que desea lograr con esto, pero su tipo de DataStruct es erróneo.

Supongo que no todos sus métodos devuelven LongValue.

struct DataStruct 
{ 
    public short ShortVale; 
    public int IntValue; 
    public long LongValue; 
    public object GetBoxedShortValue() { return ShortVale; } 
    public object GetBoxedIntValue() { return IntValue; } 
    public object GetBoxedLongValue() { return LongValue; } 
} 

De lo contrario, siempre puede usar la clase Convert para intentar convertir entre diferentes tipos.
Por ejemplo:

Convert.ToInt32(SomeObject); 

Por favor, aclarar su puesto (simplemente pulse el botón de edición y editarlo) si significaba algo diferente.

Por cierto, la conversión de object puede ser bastante propensa a errores, ya que es el tipo de base de todo. Por lo tanto, un object puede ser cualquier cosa, y eso significa que no siempre se puede convertir de manera segura un object en un int o cualquier otro tipo.

Más ejemplos:

int value; 
try 
{ 
    value = Convert.ToInt32(someObject); 
} 
catch (FormatException) 
{ 
    // the convertion is unsuccessful 
} 

Y esto también es útil:

int myValue; 
if (!int.TryParse(something, out myValue)) 
{ 
    //unsuccessful 
} 

espero que esto ayude.

+0

@Hans, Convert.ToInt32() requiere que conozca el tipo de Int en el tiempo de compilación, esto es * exactamente * lo que estoy tratando de evitar. –

0

Según lo manifestado por otros, su ejemplo no funcionará, porque usted devuelve LongValue de cada método, por lo que obtendrá una excepción de conversión no válida aquí (un recuadro largo no se puede convertir en abreviado).

newData.ShortVale = (short)data.GetBoxedShortValue(); 

Sin embargo, el uso de C# 4 dynamic, esto va a funcionar (tenga en cuenta las correcciones a sus métodos GetBoxed y dynamic en lugar de object:

// Just a simple container that returns values as objects 
struct DataStruct 
{ 
    public short ShortVale; 
    public int IntValue; 
    public long LongValue; 
    public dynamic GetBoxedShortValue() { return ShortValue; } 
    public dynamic GetBoxedIntValue() { return IntValue; } 
    public dynamic GetBoxedLongValue() { return LongValue; } 
} 

static void Main(string[] args) 
{ 
    DataStruct data; 

    // Initialize data - any value will do 
    data.LongValue = data.IntValue = data.ShortVale = 42; 

    DataStruct newData; 

    newData.ShortVale = (short)data.GetBoxedShortValue(); 
    newData.IntValue = (int)data.GetBoxedIntValue(); 
    newData.LongValue = (long)data.GetBoxedLongValue(); 

    newData.ShortVale = data.GetBoxedShortValue(); // ok 
    newData.IntValue = data.GetBoxedIntValue(); // ok 
    newData.LongValue = data.GetBoxedLongValue(); // ok 
} 

Tenga en cuenta que usted no necesita ningún moldes en la última tres casos. Tenga en cuenta también, sin embargo, que si los tipos no se alinean, como en GetBoxedShortValue() { return LongValue; }, las últimas tres líneas darán como resultado excepciones de conversión no válidas. (Es interesante que las tres primeras no funcionarán, simplemente funcionarán, pero cuando cambie dynamic de nuevo en object, ellos lanzará excepciones de conversión no válidas.)

Cuestiones relacionadas