Распаковка на неизвестный тип - PullRequest
6 голосов
/ 20 мая 2010

Я пытаюсь выяснить синтаксис, который поддерживает распаковку целочисленного типа (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)» , Поскольку объекты в конечном итоге поступают из одного и того же источника, на самом деле не может быть несоответствия (короткого! = Длинного).

Прошу прощения за надуманный пример, мне показалось, что это лучший способ продемонстрировать синтаксис.

Спасибо.

Ответы [ 4 ]

2 голосов
/ 20 мая 2010

Что ж, 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; это все еще ссылка на объект, но она также строго типизирована к исходной структуре или типу примитива.

2 голосов
/ 20 мая 2010

Я не совсем уверен, чего бы вы хотели достичь, но ваш тип 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
}

Надеюсь, это поможет.

1 голос
/ 20 мая 2010

Вы можете вернуть dynamic, который затем можно привести к целочисленному типу.

0 голосов
/ 20 мая 2010

Как утверждают другие, ваш пример не будет работать, потому что вы возвращаете 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, они будут генерировать недопустимые исключения приведения.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...