拆箱未知类型

发布于 2024-09-01 20:19:32 字数 1216 浏览 2 评论 0原文

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

我对这个人为的例子表示歉意,这似乎是演示语法的最佳方式。

谢谢。

I'm trying to figure out syntax that supports unboxing an integral type (short/int/long) to its intrinsic type, when the type itself is unknown.

Here is a completely contrived example that demonstrates the concept:

 // 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 each case, the integral types are consistent, so there should be some form of syntax that says "the object contains a simple type of X, return that as X (even though I don't know what X is)". Because the objects ultimately come from the same source, there really can't be a mismatch (short != long).

I apologize for the contrived example, it seemed like the best way to demonstrate the syntax.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

芸娘子的小脾气 2024-09-08 20:19:32

好吧,对象本身是框架所知道的最通用的类​​型。是装箱值类型(包括原始类型)还是其他类型并不重要;如果您想获得更具体的信息,您必须进行类型转换,除非您仍然处于“松散类型”的世界中,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);
    }
}

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

Well, the object in itself is the most generic type the framework knows. Whether is is a boxed value type (including primitive) or something else doesn't matter; if you want to get more specific you have to do a typecast unless you remain in the "loosely typed" world with object (or, in C# 4, dynamic).

Note, however, that you can use a list of conditions to achieve what you want:

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
}

Edit: A generic "box" may also do what you want:

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

This can then be used instead of object; it is still an object reference but it is also strongly typed to the original structure or primitive type.

庆幸我还是我 2024-09-08 20:19:32

我不完全确定你想用这个实现什么,但你的 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
}

我希望这会有所帮助。

I'm not completely sure about what you'd like to achieve with this, but your DataStruct type is errornous.

I suppose, not all of its methods return 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; }
}

Otherwise, you can always use the Convert class to try to convert between different types.
For example:

Convert.ToInt32(SomeObject);

Please clarify your post (just hit the edit button and edit it) if you meant something different.

By the way, converting from object can be quite error-prone as it is the base type of everything. So, an object can be anything, and that means that you can't always safely convert an object to an int or any other type.

More examples:

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

And this is also useful:

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

I hope this helps.

紧拥背影 2024-09-08 20:19:32

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

You can return dynamic, which can then be cast to an integral type.

心如荒岛 2024-09-08 20:19:32

正如其他人所述,您的示例将不起作用,因为您从每个方法返回 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 时,它们将会抛出无效的强制转换异常。)

As stated by others, your example won't work, because you return LongValue from each method, so you'll get an invalid cast exception here (a boxed long cannot be cast to short).

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

However, using C# 4's dynamic, this will work (note the fixes to your GetBoxed methods and dynamic rather than 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
}

Note that you don't need any casts in the last three cases. Note also, however, that if the types don't align, like in GetBoxedShortValue() { return LongValue; }, the last three lines will result in invalid cast exceptions. (Interestingly the first three won't, they'll just work, but when you change dynamic back into object, they will throw invalid cast exceptions.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文