none
Dynamic Structures The values are not assigned RRS feed

  • Question

  • I have checked this problem for years. I have two different structures that I need to pass as parameters to a common function. The two structures have within another structure that is common to both. If the root is dynamic, the values are not assigned in the internal structure.

    In the background there is also the problem that instead of having a single structure ref dynamic I have to have two structures because you cannot pass ref struct to ref dynamic or vice versa. Why?

    The interior structures are sized although it does not appear in this code.

    It does not help me to be told to think things differently because in the common function I have many things that are general to both structures and some things that are different.

    public struct St_A
    { public dynamic MyValue1;
       public string     MyValue2;

       public struct St_A1           StProp
       public struct St_COMMON StCommon;

      // Constructor.

      public St_A() : this()
      {  this.StProp       = new St_A1();
          this.StCommon = new St_COMMON();
       }

    }

    public struct St_B
    { public struct St_COMMON StCommon;

      // Constructor.

      public St_B() : this()
      {  this.StCommon = new St_COMMON();
      }

    }

    public struct St_A1
    { public dynamic MyValue3;
       public string  MyValue4;
    }

    public struct St_COMMON
    { public int Value;
    }

    MyFunction()
    { struct St_A StA = new St_A();
       struct St_B StB = new St_B();
       dynamic MyRet = Function_Common(true, ref StA, ref StB)
    }

    public static Function_Common(bool Struct_is_A, ref St_A StA, ref St_B StB)
    { dynamic MyStruct = null;

      if (Struct_is_A) MyStruct = (St_A)StA;
      else                 MyStruct = (St_B)StB;

      // This Works.
      MyStruct.MyValue1 = "10";
      MyStruct.MyValue2 = "10";

     // PROBLEM. It does not produce an error and does not assign the value. If from the debugger I perform the same action, then it is assigned.
     MyStruct.StProp.MyValue3 = "10";
     MyStruct.StProp.MyValue4 = "10";

     // PROBLEM. It does not produce an error and does not assign the value. If from the debugger I perform the same action, then it is assigned.
     MyStruct.StCommon.Value = 10;
    }





    • Edited by zequion1 Monday, September 23, 2019 3:01 PM
    Monday, September 23, 2019 10:47 AM

All replies

  • Your code is neither formatted nor valid. Please use the Insert Code Block in the toolbar to paste in your code. Also make sure it compiles as the above is not valid C# code. 

    As for your problem it is because you are misusing dynamics to try to emulate what looks like unions and that isn't how they work. While you said you don't want ppl to tell you to rethink your design it is pretty obvious you are completely misusing dynamics as a glorified variant and it isn't going to work out. There are far better, clearer and easier approaches to solving this relatively straightforward problem without any of the issues of dynamic.

    Nevertheless the issue you are having is that StProp is a struct and therefore is never null. Since you're using dynamic the underlying member provider has to return a value for the property (because dynamic doesn't know what does and doesn't exist and therefore auto creates one. So you get back a newly created struct when you reference StProp. However dynamic doesn't actually do anything with the value it simply returns it. The next time you ask for one you get a new one. Since you are getting a new value each time none of the child properties will ever be set. This is how dynamic and value types work. You cannot do this. Even ignoring dynamic this is how structs work. The following is invalid code.

    class DemoStruct
    {
      public St_A1 StProp { get; set; }
    }
    
    var demo = new DemoStruct();
    demo.StProp.MyValue3 = "10";  //Compiler ERROR

    The compiler can pick this off because it knows value types are copies and therefore you cannot change the properties of a struct like this. You have to create a new instance. Because you're using dynamic the compiler doesn't know it is a value type and therefore cannot report the error that you're seeing at runtime.

    Options include using a class for StProp instead of a struct. Then you'd get null which would at least crash your app. The alternative is to ensure StProp is set first. But since this is a value type there is no value you can check for that indicates it is already set so you need to either always initialize it or add some property to indicate it is set or not.

    MyStruct.StProp = new St_A1() { MyValue3 = "10", MyValue4 = "10" };


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, September 23, 2019 2:20 PM
    Moderator
  • I tried to simplify the code in the example. The actual structures are preconfigured and sized. One person, Dave Kreskowiak has been kind enough to tell me technically what the problem is:

    Ref struct types
    Adding the ref modifier to a struct declaration defines that instances of that type must be stack allocated. In other words, instances of these types can never be created on the heap as a member of another class. The primary motivation for this feature was Span<t> and related structures.

    The goal of keeping a ref struct type as a stack-allocated variable introduces several rules that the compiler enforces for all ref struct types.

    You can't box a ref struct. You cannot assign a ref struct type to a variable of type object, dynamic, or any interface type.
    ref struct types cannot implement interfaces.
    You can't declare a ref struct as a field member of a class or a normal struct. This includes declaring an auto-implemented property, which creates a compiler generated backing field.
    You cannot declare local variables that are ref struct types in async methods. You can declare them in synchronous methods that return Task, Task<tresult> or Task-like types.
    You cannot declare ref struct local variables in iterators.
    You cannot capture ref struct variables in lambda expressions or local functions.
    These restrictions ensure you don't accidentally use a ref struct in a manner that could promote it to the managed heap.

    You can combine modifiers to declare a struct as readonly ref. A readonly ref struct combines the benefits and restrictions of ref struct and readonly struct declarations.

    My Response:

    Where did you find that information?

    I see a great list of things that cannot be done. I want to do something simple that is to pass a structure by reference dynamically, but it doesn't work. It is a technical problem of C# that they have not solved.

    Now I have this problem and I can't find a solution other than duplicating hundreds of lines of code for each of the structures.

    Any solution?

    -----

    And "The Big Problem":

    Dave, I have this problem with Sql Server and nobody answers me. I have been working on something for years and if it is not solved, my work will be useless.

    Do you know someone who hears what I explain? Thank you

    https://social.msdn.microsoft.com/Forums/en-US/4a17a3fd-5074-4b9b-a05b-0eae7e3f44ae/sql-server-2017-transact-problems-microsoft-does-not-respond-can-you-read?forum=transactsql



    Monday, September 23, 2019 2:39 PM
  • Please do not cross post threads. Your current post is asking why your struct isn't being set properly. I explained why and how to solve it. It is unclear what the other stream you posted has to do with this. If that is a separate thread then please keep that thread together and do not cross contaminate. Please clarify what about my recommended solution doesn't solve your problem that you posted in this thread. 

    As for your DB issue you need to address that in a separate thread. This thread is about setting the properties of a struct. Thanks.


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, September 23, 2019 2:47 PM
    Moderator
  • I appreciate your response. StProp is sized in the real code. I modify the source code to see it.

    And the link:

    https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#ref-struct-types

    As I explain, it seems that this is a great limitation of the C # language. Now my only solution is to duplicate hundreds of lines for each of the two structures. I don't think it's an acceptable solution.




    • Edited by zequion1 Monday, September 23, 2019 3:05 PM
    Monday, September 23, 2019 3:02 PM
  • I don't know what you mean by sized in the real code but properties of structs cannot be set the way you were trying as I already mentioned. This is by design as structs are designed to be fast and lightweight. 

    I don't know why you're going to have to duplicate hundreds of lines of code. Generics in combination with interfaces or base classes (if not using structs) seems like it would easily solve your problem and would be easier to read than dynamics. But if the language doesn't support what you want then use C++ or something else and then call it (via P/Invoke) in C#. Every language has its limits.


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, September 23, 2019 3:08 PM
    Moderator
  • It is a problem of the goole translator.
    I have modified the code. I mean the structures are sized. I can assign values to StProp without problems, but if I next pass the structure with ref and assign it to a dynamic (because there are two structures), it seems that the C# language is very limited and has problems. Even as I say, if I enter a value and see if it has been assigned, it shows null, but if at that moment from the debugger I assign it, it does.

    I only work now in C# and it is not convenient for me to link to another language. I have worked a lot on standard C and could do it with pointers, but I don't like it, because they also advise a lot not to use them "UnSafe".

    I want to be orthodox in C#. So now I can't think of anything else.
    Monday, September 23, 2019 3:21 PM
  • If it seems to you that there is a solution, tomorrow I can generate a c # real function with the example, which I think is the same one I have set or very similar and I send it to you.
    Monday, September 23, 2019 3:24 PM
  • The ref stuff I don't think is going to help here. You're using dynamic so the actual type isn't relevant to dynamic. It sees a struct and therefore it is a struct with all the limitations therein. Is there a reason you cannot simply new up the struct fresh like I demoed as an option. This would solve the issue you have. 

    Michael Taylor http://www.michaeltaylorp3.net

    Monday, September 23, 2019 3:28 PM
    Moderator
  • The actual structures already contain information and for that reason I cannot do new.

    - If I pass the structures by value, everything works.
    - If I pass the structures by ref, everything works until I assign them to dynamic. At that time dynamic "does not know" if it contains other internal structures. That is a deficiency of the C# language.

    Structures are the most important type of C# because they allow you to accumulate and organize variables, but, can't I pass them through ref dynamic so that more than one can be used in the same function? They could work more on this issue.

    Another problem that I discover and nobody does anything to solve it. Now I am more upset with having to work on the mistakes of others.
    Tuesday, September 24, 2019 4:36 AM
  • Hi zequion1, 

    Thank you for posting here.

    I make a test based on your code, and I make struct ST_A access properties of struct ST_A1 by using an interface.

    Here’s my code:

        public interface IDATA { }
        public struct St_A
        {
            public dynamic MyValue1;
            public string MyValue2;
    
            public IDATA data;
            public T GetData<T>() where T : IDATA
            {
                return (T)data;
            }
        }
        public struct St_B
        {
        }
        public struct St_A1 : IDATA
        {
            public dynamic MyValue3;
            public string MyValue4;
        }
    
        public class Program
        {
            static void Main(string[] args)
            {
                St_A StA = new St_A();
                St_B StB = new St_B();
                Function_Common(true, ref StA, ref StB);
                Console.ReadLine();
            }
            public static void Function_Common(bool Struct_is_A, ref St_A StA, ref St_B StB)
            {
                dynamic MyStruct = null;
                if (Struct_is_A) MyStruct = (St_A)StA;
                else MyStruct = (St_B)StB;
                MyStruct.MyValue1 = "10";
                MyStruct.MyValue2 = "10";
                Console.WriteLine($"MyValue1: {MyStruct.MyValue1}, MyValue2: {MyStruct.MyValue2}");
                MyStruct.data = new St_A1();
                var v3 = MyStruct.GetData<St_A1>().MyValue3;
                v3 = "10";
                var v4 = MyStruct.GetData<St_A1>().MyValue4;
                v4 = "10";
                Console.WriteLine($"MyValue3: {v3}, MyValue4: {v4}");
            }
        }

    Result of my test:

    Hope it can help you.

    Best Regards,

    Xingyu Zhao



    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, September 24, 2019 7:14 AM
    Moderator
  •      The real structures St_A and St_B contain values before arriving at Function_Common, so I cannot initialize them before entering information using MyStruct.data = new St_A1 ();

    // What I really need is this:
    public static void Function_Common <T> (ref T MySt)
    { ref T MyStruct = ref MySt;

       // COMPILER ERROR.StProp Not Exists.
       MyStruct.StProp.
    Value1 = "10";
    }

    OR

    public static void Function_Common <T> (ref T MySt)
    { // COMPILER ERROR.StProp Not Exists.
      
    MySt .StProp.Value1 = "10";
    }

    // More things I've tried.
    public static void Function_Common <T> (ref T St_A)
    { // PROBLEM. It does not produce an error and does not assign the value. If from the debugger I perform the same action, then it is assigned.
          dynamic MyStruct = System.Activator.CreateInstance<T>();
          MyStruct = St_A;

      // Here it cannot be argued that "the content of the structure is unknown" and that for that reason the values are not assigned.
          MyStruct.StProp.Value1 = "10";
    }





    • Edited by zequion1 Tuesday, September 24, 2019 8:59 AM
    Tuesday, September 24, 2019 8:53 AM
  • That's how structures work. They weren't designed to do what you're trying to do. There are a couple of solutions I can see.

    1) Use a class instead. Classes would work just fine with this. Is there a reason you aren't using them instead of structs?

    2) Implement ICloneable on the struct and clone the current object so you can set the new values. That is what this interface is designed for.

    3) Stop using dynamic and use interfaces and generics instead. I'm still struggling to understand why you'd use dynamic here. Dynamic is for allowing you to dynamically add and remove properties on an arbitrary object. You don't seem to be using that here, you're using it as a glorified general object. In that case just use object and rely on reflection or typechecking to figure out what you have. That wouldn't solve the specific assignment problem you're having but you'd at least be getting compiler errors like you want to let you know what is wrong.


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, September 24, 2019 1:33 PM
    Moderator
  • All that complicates the use of structures even if it is true.

    In any case, it is certain that the structures lack more programming because I am seeing things that are badly finished as I am already explaining.
    Tuesday, September 24, 2019 1:49 PM
  • Structures are designed for the simple case of combining values less than 64 bytes with no heavy construction, pre-built equality, etc. If anything steps outside that then a class is the correct solution. This is how the CLR was built and it makes sense. If structs aren't doing what you need then you have to upgrade or live with the limits. 

    I've done all I can for this post. I'm going to let others help you know if they have any better ideas.


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, September 24, 2019 2:01 PM
    Moderator
  • I do not doubt it but what I say is that the structures need more programming because now they have an incoherent or improvable operation and that would help us all
    Tuesday, September 24, 2019 2:06 PM
  • Hi zequion1,

    Thanks for your feedback.

    Based on your description, I suggest that you can report a problem in Developer Community forum for more help.

    Thank you for your understanding.

    Best Regards,

    Xingyu Zhao


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, September 25, 2019 8:35 AM
    Moderator