How come C# can handle this obviously idiotic object promotion during run time?
Asked Answered
G

1

7

I like the C# language very much. I'm just playing around, and would never use the code below in production code. Obviously the compiler is fooled by the layout of the struct. But how come, that the string on the Super class can still be written and read in run-time? I would have expected some memory access violation. Inspecting the type during run time, it says it is of type Base, see the NoProblem() function execution. No Super class has been instantiated.

How is it able to function like this?

using System;
using System.Runtime.InteropServices;

namespace Fiddle
{
    class Program
    {
        static void Main(string[] args)
        {
            var b = new Base
            {
                IntOnBase = 1
            };
            var overlay = new Overlay();
            overlay.Base = b;
            var super = overlay.Super;
            var intValue = super.IntOnBase;
            super.StringOnSuper = "my test string";
            var stringValue = super.StringOnSuper;
            super.NoProblem();
            Expressions.Fiddle();
        }
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct Overlay
    {
        [FieldOffset(0)]
        public Super Super;
        [FieldOffset(0)]
        public Base Base;
    }

    public class Super : Base
    {
        public string StringOnSuper { get; set; }

        public void NoProblem()
        {
            Console.WriteLine("You know, I am really a " + this.GetType().Name + " kind of class.");
        }
    }

    public class Base
    {
        public int IntOnBase { get; set; }
    }
}
Gissing answered 7/4, 2017 at 14:20 Comment(5)
Super is larger than Base and you would only get an issue if you tried to cast Super to BaseBr
What's the value of super.StringOnSuper before you assign it? I'd expect it to be uninitialized, since the constructor of Base does not know it.Godfrey
Seems similar to this question. Some people suggest that use of FieldOffset should be deemed unsafe.Worth
Also seen on this questionAcanthoid
It is just not a C# feature, the language spec does not once mention it. This is a capability exposed by the CLR. It has a very practical need, this declares a union, a type available in many other languages. But not C#, unions are fundamentally type-unsafe. Gets lots of use in for example the winapi, they could not have written the .NET Framework without it. Above pure, C# is also a very practical language that solves real programming problems. The real world is not pure.Frustrated
O
0

Well you told the CLR to lay out the memory in advance by using StructLayout (I should caveat this saying this is based on my learning today after experimenting and reading the other answers suggested)

You can tell here that the CLR is not actually instantiating anything. This will throw a NPE. And you can play around with the the constructor on super. It isn't getting invoked, and won't.

Basically you are directly accessing memory, and since string, int etc are all built in types you are safely interacting with them. This should probably require more "intention" by the user, and the other commented questions are all pointing to this requiring an unsafe declaration.

class Program
{
    static void Main(string[] args)
    {
        var b = new Base
        {
            IntOnBase = 1
        };
        var overlay = new Overlay();
        overlay.Base = b;
        var super = overlay.Super;
        var intValue = super.IntOnBase;
        super.StringOnSuper = 8;
        var stringValue = super.StringOnSuper;
        System.Diagnostics.Debug.WriteLine(stringValue);
        super.NoProblem();
    }
}

[StructLayout(LayoutKind.Explicit)]
public struct Overlay
{
    [FieldOffset(0)]
    public Super Super;
    [FieldOffset(0)]
    public Base Base;
}
public class NewClass
{
    public string cat { get; set; }
}
public class Super : Base
{
    private Super imNull;
    public Super()
    {
       // imNull = new Super();
        System.Diagnostics.Debug.WriteLine("well i get initialized...");
    }
    public int StringOnSuper { get; set; }

    public void NoProblem()
    {
        System.Diagnostics.Debug.Write("You know, I am really a " + this.GetType().Name + " kind of class. But my super is " + imNull.ToString() );
    }
}

public class Base
{
    public int IntOnBase { get; set; }
}
Outfight answered 7/4, 2017 at 15:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.