By Mark T


2008-09-16 01:45:44 8 Comments

Is it possible in C# to have a Struct with a member variable which is a Class type? If so, where does the information get stored, on the Stack, the Heap, or both?

4 comments

@Craig Eddy 2008-09-16 02:12:00

It's probably not a recommended practice to do so: see http://msdn.microsoft.com/en-us/library/ms229017(VS.85).aspx

Reference types are allocated on the heap, and memory management is handled by the garbage collector.

Value types are allocated on the stack or inline and are deallocated when they go out of scope.

In general, value types are cheaper to allocate and deallocate. However, if they are used in scenarios that require a significant amount of boxing and unboxing, they perform poorly as compared to reference types.

@Ry- 2013-09-07 01:51:39

Could you summarize why in your answer, please? (Links go dead, and all that.)

@supercat 2012-08-09 16:14:14

If one of the fields of a struct is a class type, that field will either hold the identity of a class object or else a null referece. If the class object in question is immutable (e.g. string), storing its identity will effectively also store its contents. If the class object in question is mutable, however, storing the identity will be an effective means of storing the contents if and only if the reference will never fall into the hands of any code which might mutate it once it is stored in the field.

Generally, one should avoid storing mutable class types within a structure unless one of two situations applies:

  1. What one is interested in is, in fact, the identity of the class object rather than its content. For example, one might define a `FormerControlBounds` structure which holds fields of type `Control` and `Rectangle`, and represents the `Bounds` that control had at some moment in time, for the purpose of being able to later restore the control to its earlier position. The purpose of the `Control` field would not be to hold a copy of the control's state, but rather to identify the control whose position should be restored. Generally the struct should avoid accessing any mutable members of the object to which it holds a reference, except in cases where it is clear that such access is referring to the current mutable state of the object in question (e.g. in a `CaptureControlPosition` or `RestoreControlToCapturedPosition` method, or a `ControlHasMoved` property).
  2. The field is `private`, the only methods which read it do so for the purpose of examining its properties without exposing the object itself it to outside code, and the only methods which write it will create a new object, perform all of the mutations that are ever going to happen to it, and then store a reference to that object. One could, for example, design a `struct` which behaved much like an array, but with value semantics, by having the struct hold an array in a private field, and by having every attempt to write the array create a new array with data from the old one, modify the new array, and store the modified array to that field. Note that even though the array itself would be a mutable type, every array instance that would ever be stored in the field would be effectively immutable, since it would never be accessible by any code that might mutate it.

Note that scenario #1 is pretty common with generic types; for example, it's very common to have a dictionary whose "values" are the identities of mutable objects; enumerating that dictionary will return instances of KeyValuePair whose Value field holds that mutable type.

Scenario #2 is less common. There is alas no way to tell the compiler that struct methods other than property setters will modify a struct and their use should thus be forbidden in read-only contexts; one could have a struct that behaved like a List<T>, but with value semantics, and included an Add method, but an attempt to call Add on a read-only struct instance would generate bogus code rather than a compiler error. Further, mutating methods and property setters on such structs will generally perform rather poorly. Such structs can be useful are when they exist as an immutable wrapper on an otherwise-mutable class; if such a struct is never boxed, performance will often be better than a class. If boxed exactly once (e.g. by being cast to an interface type), performance will generally be comparable to a class. If boxed repeatedly, performance can be much worse than a class.

@Eric Z Beard 2008-09-16 01:53:07

Yes, you can. The pointer to the class member variable is stored on the stack with the rest of the struct's values, and the class instance's data is stored on the heap.

Structs can also contain class definitions as members (inner classes).

Here's some really useless code that at least compiles and runs to show that it's possible:

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyStr m = new MyStr();
            m.Foo();

            MyStr.MyStrInner mi = new MyStr.MyStrInner();
            mi.Bar();

            Console.ReadLine();
        }
    }

    public class Myclass
    {
        public int a;
    }

    struct MyStr
    {
        Myclass mc;

        public void Foo()
        {
            mc = new Myclass();
            mc.a = 1;
        }

        public class MyStrInner
        {
            string x = "abc";

            public string Bar()
            {
                return x;
            }
        }
    }
}

@James M 2017-01-14 11:02:44

Just curious, why did you cross out stack? Don't structs store all their data on the stack, including pointers to reference members as in this scenario?

@lozzajp 2017-02-28 12:03:42

@Ben Voigt 2011-07-23 15:53:20

The class content gets stored on the heap.

A reference to the class (which is almost the same as a pointer) gets stored with the struct content. Where the struct content is stored depends on whether it's a local variable, method parameter, or member of a class, and whether it's been boxed or captured by a closure.

@RBT 2017-04-11 01:04:26

Glad that you mentioned that storage varies with the type of the identifier (local variable, parameter or member). +1.

Related Questions

Sponsored Content

18 Answered Questions

[SOLVED] What's the difference between struct and class in .NET?

9 Answered Questions

[SOLVED] Random number generator only generating one random number

  • 2009-04-20 12:11:24
  • Ivan Prodanov
  • 149484 View
  • 671 Score
  • 9 Answer
  • Tags:   c# random

26 Answered Questions

[SOLVED] Why not inherit from List<T>?

16 Answered Questions

[SOLVED] Are static class variables possible?

25 Answered Questions

[SOLVED] When should you use a class vs a struct in C++?

  • 2008-09-10 16:29:54
  • Alan Hinchcliffe
  • 331313 View
  • 762 Score
  • 25 Answer
  • Tags:   c++ oop class struct ooad

8 Answered Questions

[SOLVED] How to loop through all enum values in C#?

7 Answered Questions

[SOLVED] Static vs class functions/variables in Swift classes?

28 Answered Questions

[SOLVED] When to use struct?

  • 2009-02-06 17:37:55
  • Alex Baranosky
  • 232667 View
  • 1234 Score
  • 28 Answer
  • Tags:   c# struct

16 Answered Questions

[SOLVED] How to get the type of T from a member of a generic class or method?

  • 2009-02-17 15:24:36
  • Patrick Desjardins
  • 518268 View
  • 571 Score
  • 16 Answer
  • Tags:   c# .net generics

8 Answered Questions

[SOLVED] Does using "new" on a struct allocate it on the heap or stack?

Sponsored Content