Unboxing to an unknown type

I am trying to understand a syntax that supports unboxing of an integral type (short / int / long) in its internal type when the type itself is unknown.

Here is a completely contrived example demonstrating the concept:

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

In each case, the integral types are consistent, so there should be some syntax that states: "The object contains a simple type X, returns it as X (although I do not know what X is)", since the objects ultimately come from one source, there really cannot be a mismatch (short! = Long).

I apologize for the far-fetched example, this is the best way to demonstrate the syntax.

Thanks.

+6
object c # inferred-type
source share
4 answers

Well, object itself is the most common type that structure knows. Is the type of box value (including primitive) or something else unimportant; if you want to get more specific information, you should make a typecast if you don’t stay in the "weakly typed" world with object (or in C # 4, dynamic ).

Please note, however, that you can use the list of conditions to achieve the desired result:

 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 } 

Edit: A generic β€œbox” can also do what you want:

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

Then it can be used instead of object ; it is still an object reference, but it is also strongly typed for the original structure or primitive type.

+2
source share

I'm not quite sure what you would like to achieve with this, but your DataStruct type is erroneous.

I suppose not all of his methods return 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; } } 

Otherwise, you can always use the Convert class to convert between different types.
For example:

 Convert.ToInt32(SomeObject); 

Clarify your post (just click the edit button and edit it) if you meant something else.

By the way, the conversion from object can be quite error prone, as it is the base type of everything. Thus, object can be anything, and this means that you cannot always safely convert object to int or any other type.

Other examples:

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

And it is also useful:

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

Hope this helps.

+2
source share

You can return dynamic , which can then be ported to an integral type.

+1
source share

As pointed out by others, your example will not work because you are returning a LongValue from each method, so you will get an invalid listing exception here (boxed long cannot be shortened).

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

However, using C # 4 dynamic , this will work (note the fixes for the GetBoxed and dynamic methods, not the 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 } 

Note that you do not need castes in the last three cases. However, also note that if the types are not aligned, as in GetBoxedShortValue() { return LongValue; } GetBoxedShortValue() { return LongValue; } , the last three lines lead to invalid exception exceptions. (Interestingly, the first three will not, they will work, but when you change dynamic to object , they will throw invalid exception exceptions.)

0
source share

All Articles