سؤال

أحاول اكتشاف بناء الجملة الذي يدعم إلغاء الالتفاف نوعًا متكاملًا (قصير/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, أنهم سوف يرمي استثناءات مصبوب غير صالحة.)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top