Why can I not modify the result of an unboxing conversion?

后端 未结 3 1332
说谎
说谎 2020-12-01 22:04
struct Point
{
    public int x;
    public int y;
}
void Main()
{
    Point p;
    p.x = 1;
    p.y = 1;
    Object o = p;
    ((Point) o).x = 4; // error
    ((Poi         


        
相关标签:
3条回答
  • 2020-12-01 22:50

    You can't do this, because the result of unboxing is a copy of the boxed value, not the boxed value itself. And casting object to a value type is the definition of unboxing. So, if the compiler allowed you to do this, it would be very confusing, because the assignments wouldn't actually do anything.

    I think the reason your code works in C++/CLI is because that language in general has more support for working (or not) with references, including strongly-typed boxes (e.g. Point^) and treating (some) classes as value types (e.g. using MemoryStream without ^).

    0 讨论(0)
  • 2020-12-01 22:52

    Because of how value types work, the boxed Point is a copy of the original, and "unboxing" it by casting back to Point creates yet another copy. From the C# language spec (§1.3, "Types and Variables"):

    When a value of a value type is converted to type object, an object instance, also called a “box,” is allocated to hold the value, and the value is copied into that box. Conversely, when an object reference is cast to a value type, a check is made that the referenced object is a box of the correct value type, and, if the check succeeds, the value in the box is copied out.

    Modifying the copy wouldn't change the original anyway, so it wouldn't make much sense to allow it.

    As for C++...well...of course, the rules of C# don't necessarily apply to it. :) The CLR actually has quite a bit more flexibility with pointers and references than you'd first think, and C++ -- being known for such flexibility -- probably takes advantage of it.

    0 讨论(0)
  • 2020-12-01 23:06

    You can accomplish this using the System.Runtime.CompilerService.Unsafe.Unbox function:

        static void Main()
        {
            Point p;
            p.x = 1;
            p.y = 1;
            Object o = p;
            Unsafe.Unbox<Point>(o).x = 6; // error
            p = (Point)o;  // 6
            Console.WriteLine(p.x);
        }
    

    As the documentation notes, and I presume the reason it is considered unsafe, is that you must not do this with an immutable built-in type [e.g. Unbox<int>(i) = 42], and the system does nothing to enforce this.

    0 讨论(0)
提交回复
热议问题