2010-05-19 108 views
6

我試圖找出當它的類型本身是未知的時候支持拆箱整型(short/int/long)到其內在類型的語法。拆箱到未知類型

下面是一個說明的概念的完全人爲的例子:

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

在每種情況下,積分的類型是一致的,所以應該有某種形式的句法,說:「該對象包含一個簡單的類型的X,返回X(即使我不知道X是什麼)「。因爲對象最終來自同一個來源,所以實際上不會有不匹配(short!= long)。

我爲這個人爲的例子表示歉意,它似乎是展示語法的最好方式。

謝謝。

+0

所有的你'GetBoxed'方法返回'LongValue'。錯字? – unholysampler 2010-05-19 20:21:22

+0

你是什麼意思「不可能有不匹配」?如果你知道這個類型,那麼就不會有;如果你不這樣做,那麼可以。 – 2010-05-19 20:21:49

+1

你想如何使用拆箱的結果?如果拆箱後你不知道這種類型,那麼你就無法做任何事情(除了猜測和使用'dynamic')。如果您在拆箱後知道該類型,請將其取消裝箱。在你的榜樣,你知道newData.IntValue只能與一個int被分配,讓你_have_做'newData.IntValue =(int)的yourUnknownBoxedValue;'。如果這樣做失敗,則不能將其分配給newData.IntValue。如果它沒有失敗,那麼你很好。 所以我說的是真的:你應該想出一個沒有人爲的例子,因爲這沒有意義。 – Joren 2010-05-19 20:39:50

回答

2

那麼,object本身是框架知道的最通用的類​​型。無論是盒裝價值類型(包括原始)還是別的什麼都不重要;如果你想得到更具體的你做一個類型轉換,除非你仍然在「鬆散類型」的世界object(或在C#4,dynamic)。

但是請注意,您可以使用的條件列表來實現你想要的:

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 
} 

編輯:一個通用的「盒子」還可以做你想做的:

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

這可以用來代替object;它仍然是一個對象引用,但它也是強類型的原始結構或原始類型。

+0

作爲邊注,框架已經包含非常相似'盒'一類(儘管沒有轉換運算符和IConvertible):'StrongBox的'(System.Runtime.CompilerServices)。 – Ruben 2010-05-19 20:45:40

1

您可以返回dynamic,然後可以將其轉換爲整數類型。

2

我不完全確定你想用這個來實現什麼,但是你的DataStruct類型是錯誤的。

我想,並非所有的方法都返回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; } 
} 

否則,您可以隨時使用Convert類嘗試在不同類型之間進行轉換。
例如:

Convert.ToInt32(SomeObject); 

請說明您的文章(只需點擊編輯按鈕和編輯)如果你的意思是不同的東西。

順便說一句,從object轉換可能是相當容易出錯,因爲它是一切的基本類型。所以,object可以是任何東西,這意味着你不能總是安全地將object轉換爲int或任何其他類型。

更多的例子:

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

,這也是有用:

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

我希望這有助於。

+0

@Hans,Convert.ToInt32()要求你在編譯時知道Int類型 - 這正是*我試圖避免的。 – 2011-04-07 01:27:45

0

如前所述別人,你的榜樣是行不通的,因爲你從每個方法返回的longValue,所以你會在這裏得到一個無效轉換異常(一盒裝長期不能轉換到短)。

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

然而,使用C#4的dynamic,這將工作(注意修復您GetBoxed方法和dynamic,而不是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 
} 

請注意,您不需要在過去的任何類型轉換三種情況。還要注意,但是,如果該類型不對齊,像GetBoxedShortValue() { return LongValue; },最後三行會導致無效轉換異常。(有趣的是,前三個都不會,他們只會工作,但是當你將dynamic改回object,他們將引發無效轉換異常。)