Domanda

Sto cercando di capire sintassi che supporti unboxing di un tipo integrale (breve / int / lungo) per il suo tipo intrinseco, quando il tipo di per sé non è nota.

Ecco un esempio del tutto artificiosa che dimostra il concetto:

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

In ogni caso, i tipi integrali sono coerenti, quindi non ci dovrebbe essere una qualche forma di sintassi che dice "l'oggetto contiene un semplice tipo di X, ritorno che come X (anche se non so che cosa è X)" . Poiché gli oggetti in ultima analisi, provengono dalla stessa fonte, in realtà non può essere una mancata corrispondenza (breve! = Lungo).

Mi scuso per l'esempio forzato, sembrava che il modo migliore per dimostrare la sintassi.

Grazie.

È stato utile?

Soluzione

Bene, il object in sé è il tipo più generica quadro sa. Se è un tipo di valore in scatola (compresi primitiva) o qualcos'altro non importa; Se si desidera ottenere maggiori specifico che sono di fare un typecast se non rimanete nel mondo "debolmente tipizzato" con object (o, in C # 4, dynamic).

Si noti, tuttavia, che è possibile utilizzare un elenco di condizioni per ottenere ciò che si vuole:

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
}

Modifica Una "scatola" generico può anche fare quello che vuoi:

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

Questo può quindi essere usato al posto di object; è ancora un riferimento all'oggetto ma è anche fortemente tipizzato alla struttura originale o tipo primitivo.

Altri suggerimenti

Non sono del tutto sicuro di quello che si desidera ottenere con questo, ma il tipo di DataStruct è errornous.

suppongo, non tutti i suoi metodi restituiscono 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; }
}

In caso contrario, si può sempre utilizzare la classe Convert per cercare di convertire tra diversi tipi.
Ad esempio:

Convert.ToInt32(SomeObject);

Si prega di chiarire tuo post (basta premere il pulsante Modifica e modificarlo) se si intende qualcosa di diverso.

A proposito, conversione da object può essere molto soggetto ad errori in quanto è il tipo di base di tutto. Così, un object può essere qualsiasi cosa, e ciò significa che non si può sempre convertire in modo sicuro un object ad un int o di qualsiasi altro tipo.

Altri esempi:

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

E questo è anche utile:

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

Spero che questo aiuta.

È possibile tornare dynamic, che possono poi essere gettato in un tipo integrale.

Come già detto da altri, il tuo esempio non funzionerà, perché ritorni LongValue da ogni metodo, quindi si otterrà un'eccezione getto valida qui (un boxed lungo non può essere lanciato a breve).

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

Tuttavia, utilizzando C # 4 di dynamic, questo lavoro la volontà (notare le correzioni per i metodi e le dynamic piuttosto che object GetBoxed:

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

Si noti che non è necessario alcun calchi in questi ultimi tre casi. Si noti anche, però, che se i tipi non si allineano, come in GetBoxedShortValue() { return LongValue; }, le ultime tre righe si tradurrà in eccezioni del cast non validi. (È interessante notare che i primi tre non lo faranno, faranno solo il lavoro, ma quando si cambia di nuovo dynamic in object, che getterà le eccezioni del cast non valido.)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top