C# 取消装箱到未知类型

C# 取消装箱到未知类型,c#,.net,object,unboxing,inferred-type,C#,.net,Object,Unboxing,Inferred Type,我试图找出当类型本身未知时,支持将整型(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 GetBoxedS

我试图找出当类型本身未知时,支持将整型(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是什么)”。因为对象最终来自同一个源,所以不可能存在不匹配(short!=long)

我为这个人为的例子道歉,它似乎是演示语法的最佳方式


谢谢。

您可以返回
dynamic
,然后可以将其转换为整数类型。

嗯,
对象本身就是框架知道的最通用的类型。是装箱值类型(包括原语)还是其他类型并不重要;如果你想变得更具体,你必须进行类型转换,除非你仍然使用
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 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);
    }
}
公共类框:IConvertible,其中T:struct,IConvertible{
公共静态隐式运算符T(方框){
返回装箱。值;
}
公共静态显式运算符框(T值){
返回新框(值);
}
私有只读T值;
公用箱(T值){
这个值=值;
}
公共价值{
得到{
返回值;
}
}
公共覆盖布尔等于(对象对象对象){
装箱=obj作为箱子;
如果(已装箱!=null){
返回值.Equals(装箱的.value);
}
返回值。等于(obj);
}
公共覆盖int GetHashCode(){
返回值。GetHashCode();
}
公共重写字符串ToString(){
返回值.ToString();
}
bool IConvertible.ToBoolean(IFormatProvider提供程序){
返回值.ToBoolean(提供程序);
}
char IConvertible.ToChar(IFormatProvider){
返回值.ToChar(提供者);
}
sbyte IConvertible.ToSByte(IFormatProvider){
返回值.ToSByte(提供程序);
}
字节IConvertible.ToByte(IFormatProvider){
返回值.ToByte(提供程序);
}
短IConvertible.ToInt16(IFormatProvider){
返回值.ToInt16(提供程序);
}
ushort IConvertible.ToUInt16(IFormatProvider){
返回值.ToUInt16(提供者);
}
int IConvertible.ToInt32(IFormatProvider){
返回值.ToInt32(提供程序);
}
uint IConvertible.ToUInt32(IFormatProvider提供程序){
返回值.ToUInt32(提供程序);
}
long IConvertible.ToInt64(IFormatProvider){
返回值.ToInt64(提供程序);
}
ulong IConvertible.ToUInt64(IFormatProvider提供程序){
返回值.ToUInt64(提供程序);
}
浮点IConvertible.ToSingle(IFormatProvider){
返回值.ToSingle(提供程序);
}
双IConvertible.ToDouble(IFormatProvider){
返回值.ToDouble(提供程序);
}
十进制IConvertible.ToDecimal(IFormatProvider提供程序){
返回值.ToDecimal(提供程序);
}
DateTime IConvertible.ToDateTime(IFormatProvider提供程序){
返回值.ToDateTime(提供程序);
}
字符串IConvertible.ToString(IFormatProvider提供程序){
返回值.ToString(提供程序);
}
对象IConvertible.ToType(类型转换类型,IFormatProvider提供程序){
返回值.ToType(conversionType,provider);
}
}

然后可以使用它来代替
对象
;它仍然是一个对象引用,但它也是原始结构或基元类型的强类型。

我不完全确定您希望用它实现什么,但您的数据结构类型是错误的

我想,并不是所有的方法都返回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);
如果你的意思不同,请澄清你的帖子(只需点击编辑按钮并编辑它)

顺便说一下,从
对象
转换可能非常容易出错,因为它是所有内容的基本类型。因此,
对象
可以是任何东西,这意味着您不能总是安全地将
对象
转换为int或任何其他类型

更多示例:

int value;
try
{
    value = Convert.ToInt32(someObject);
}
catch (FormatException)
{
    // the convertion is unsuccessful
}
这也很有用:

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

我希望这会有所帮助。

正如其他人所说,您的示例将不起作用,因为您从每个方法返回LongValue,因此您将在这里得到一个无效的强制转换异常(装箱的long不能强制转换为short)

但是,使用C#4的
dynamic
,这将起作用(注意对GetBoxed方法和
dynamic
的修复,而不是
对象的修复):

// 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
时,它们将抛出无效的强制转换异常。)

所有
GetBoxed
方法都返回
LongValue
。输入错误?什么意思是“不可能存在不匹配”?如果您知道类型,则不可能;如果您不知道,则可能存在。您希望如何使用取消装箱的结果?如果您在取消装箱后不知道类型,则无法对其执行任何操作(除了猜测和使用
动态
)。如果在取消装箱后确实知道该类型,则取消装箱到该类型。在您的示例中,您知道newData.IntValue只能分配一个