unboxing لنوع غير معروف
-
03-10-2019 - |
سؤال
أحاول اكتشاف بناء الجملة الذي يدعم إلغاء الالتفاف نوعًا متكاملًا (قصير/int/طويل) إلى نوعه الجوهري ، عندما يكون النوع نفسه غير معروف.
فيما يلي مثال مفتعل تمامًا يوضح المفهوم:
// 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)". لأن الكائنات تأتي في النهاية من نفس المصدر ، لا يمكن أن يكون هناك بالفعل عدم تطابق (قصير! = طويل).
أعتذر عن المثال المفترض ، بدا الأمر أفضل طريقة لإظهار بناء الجملة.
شكرًا.
المحلول
حسنا ، و 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
; ؛ لا يزال مرجعًا للكائن ولكنه يتم كتابته أيضًا بقوة إلى الهيكل الأصلي أو النوع البدائي.
نصائح أخرى
لست متأكدًا تمامًا مما ترغب في تحقيقه مع هذا ، لكن نوع البيانات الخاص بك خطأ.
أفترض ، ليس كل أساليبها تعود 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.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
}
آمل أن يساعد هذا.
يمكنك العودة dynamic
, ، والتي يمكن بعد ذلك إلقاءها على نوع متكامل.
كما ذكر الآخرون ، لن يعمل مثالك ، لأنك تعيد 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
, أنهم سوف يرمي استثناءات مصبوب غير صالحة.)