2010-05-19 34 views
6

Tôi đang cố gắng tìm ra cú pháp hỗ trợ unboxing một loại tích phân (ngắn/int/long) thành kiểu nội tại của nó, khi chính loại đó chưa được biết.Unboxing to unknown type

Dưới đây là một ví dụ hoàn toàn giả tạo đó chứng tỏ các khái niệm:

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

Trong mỗi trường hợp, các loại không thể thiếu phù hợp, vì vậy cần có một số hình thức cú pháp nói rằng "đối tượng chứa một loại đơn giản X, trả về X (mặc dù tôi không biết X là gì) ". Bởi vì các đối tượng cuối cùng đến từ cùng một nguồn, có thực sự không thể là một không phù hợp (ngắn! = Dài).

Tôi xin lỗi vì ví dụ giả tạo này, có vẻ như cách tốt nhất để chứng minh cú pháp.

Cảm ơn.

+0

Tất cả các phương thức 'GetBoxed' đều trả về' LongValue'. Typo? – unholysampler

+0

Ý bạn là "không thể không khớp"? Nếu bạn biết loại, thì không thể có; nếu không, thì có thể. –

+1

Bạn muốn sử dụng kết quả unboxing của mình như thế nào? Nếu bạn không biết loại sau khi unboxing, sau đó bạn không thể làm bất cứ điều gì với nó (ngoài việc đoán và sử dụng 'năng động'). Nếu bạn biết loại sau khi unboxing, sau đó unbox để loại đó. Trong ví dụ của bạn, bạn biết rằng newData.IntValue chỉ có thể được gán với một int, do đó bạn _have_ để làm 'newData.IntValue = (int) yourUnknownBoxedValue;'. Nếu điều này sau đó không thành công, bạn không thể gán nó cho newData.IntValue. Nếu nó không thất bại, thì bạn ổn. Vì vậy, những gì tôi đang nói là thực sự: bạn nên nghĩ ra một ví dụ không phải là giả tạo, bởi vì điều này không có ý nghĩa. – Joren

Trả lời

2

Vâng, chính bản thân mẫu object là loại chung nhất mà khung làm việc biết. Cho dù là một loại giá trị đóng hộp (bao gồm nguyên thủy) hoặc cái gì khác không quan trọng; nếu bạn muốn cụ thể hơn, bạn để tạo kiểu chữ trừ khi bạn vẫn ở trong thế giới "được nhập sai" với object (hoặc, trong C# 4, dynamic).

Lưu ý, tuy nhiên, bạn có thể sử dụng một danh sách các điều kiện để đạt được những gì bạn muốn:

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: Một generic "hộp" cũng có thể làm những gì bạn muốn:

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

Điều này có thể được sử dụng thay vì object; nó vẫn là một tham chiếu đối tượng nhưng nó cũng được gõ mạnh vào cấu trúc ban đầu hoặc kiểu nguyên thủy.

+0

Là một lưu ý phụ, Khung đã chứa một lớp đáng kể tương tự như 'Box '(mặc dù không có toán tử chuyển đổi và IConvertible):' StrongBox '(System.Runtime.CompilerServices). – Ruben

1

Bạn có thể trả lại dynamic, sau đó có thể truyền sang loại không thể tách rời.

2

Tôi không hoàn toàn chắc chắn về những gì bạn muốn đạt được với điều này, nhưng loại DataStruct của bạn là sai lầm.

Tôi cho rằng, không phải tất cả các phương thức của nó đều trả về 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; } 
} 

Nếu không, bạn luôn có thể sử dụng lớp Chuyển đổi để cố chuyển đổi giữa các loại khác nhau.
Ví dụ:

Convert.ToInt32(SomeObject); 

Xin làm rõ bài viết của bạn (chỉ cần nhấn vào nút chỉnh sửa và chỉnh sửa nó) nếu bạn có nghĩa là một cái gì đó khác nhau.

Nhân tiện, việc chuyển đổi từ object có thể khá dễ bị lỗi vì đây là loại cơ sở của mọi thứ. Vì vậy, một object có thể là bất kỳ điều gì và điều đó có nghĩa là bạn không thể luôn chuyển đổi an toàn một số object thành một loại int hoặc bất kỳ loại nào khác.

Thêm ví dụ:

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

Và điều này cũng rất hữu ích:

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

Tôi hy vọng điều này sẽ giúp.

+0

@Hans, Convert.ToInt32() yêu cầu bạn biết loại Int tại thời gian biên dịch - đây là * chính xác * những gì tôi đang cố gắng tránh. –

0

Như đã nêu bởi những người khác, ví dụ của bạn sẽ không hoạt động, bởi vì bạn trả về LongValue từ mỗi phương pháp, vì vậy bạn sẽ nhận được một ngoại lệ cast không hợp lệ ở đây (một hộp dài không thể được đúc ngắn).

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

Tuy nhiên, sử dụng C# 4 của dynamic, điều này sẽ làm việc (lưu ý các bản sửa lỗi cho các phương pháp GetBoxed của bạn và dynamic hơn 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 
} 

Lưu ý rằng bạn không cần bất kỳ phôi trong cuối cùng Tuy nhiên, hãy lưu ý rằng nếu các loại không căn chỉnh, như trong GetBoxedShortValue() { return LongValue; }, ba dòng cuối cùng sẽ dẫn đến ngoại lệ truyền không hợp lệ. (Điều thú vị là ba dòng đầu tiên sẽ không hoạt động, nhưng khi bạn thay đổi dynamic trở lại vào object, họ sẽ ném ngoại lệ truyền không hợp lệ.)

Các vấn đề liên quan