More On Structs

by KodefuGuru 8. June 2009 12:07

On Friday, I wrote a post that listed guidelines for when to use a struct rather than a class. A commenter of that blog entry asked me to elaborate on the 16-byte rule.

There is a special class in the .NET framework called ValueType. You can't actually inherit from this class nor can you use it as a generic constraint, but you can use it for variable and parameter declarations when you don't want to accept a reference type. There are two type of constructs that inherit from this class: structs and enums.

        static void Main(string[] args)
        {
            
//It will accept structs
            ParameterTest(0);
            
//It will accept enums
            ParameterTest(TypeCode.Boolean);
            
//It won't accept reference types
            ParameterTest("This line doesn't work");
        }

        
static void ParameterTest(ValueType value)
        {
            
Console.WriteLine(value);
        }

Unlike other objects (referred to as reference types), value types go on the stack rather than the heap. The benefits of using the stack are that operations on it are faster, the disadvantage is that there's less memory. Despite the shortage of memory, it isn't going to be an issue the majority of the time unless you're creating tons of these objects. What is an issue is the immutable nature of value types. Every time a modification is made to the object, it creates a new one. Every time you pass the object to a method, it creates a new one. With a large struct, this can be an issue with the default 1 MB you have for the stack. It's also likely that 32-bit processors' operations can handle 16 bytes of memory better than larger sizes, but I lack the expertise on processors to definitively make this claim. If this is the case, 64-bit processors will better handle larger structs.

I am opposed to creating structs with reference type members, and for this reason I'm opposed to creating structs wth string members. Reference members indicate that the value type doesn't really represent a "value." However, if you were to include one it would take up as much space as the reference to the heap takes up. In the case of the Address example in the prior post, the struct size would be 20 bytes - 4 bytes per string on a 32-bit processor.

If you include an mutable reference type as a member on a struct, you run into another problem. The rules of mutability no longer apply, as the reference will still refer to the same memory location.

    class Program
    {
        
static void Main(string[] args)
        {
            
Test test = new Test(1);
            Change(test);

            
//Writes 9 to the screen
            Console.WriteLine(test.ReferenceType.Number);
        }

        
static void Change(Test test)
        {
            test.ReferenceType.Number = 9;
        }
    }

    
struct Test
    {
        
private ReferenceType referenceType;

        
public ReferenceType ReferenceType
        {
            
get { return referenceType; }
            
set { referenceType = value; }
        }

        
public Test(int a)
        {
            referenceType =
new ReferenceType();
            referenceType.Number = a;
        }
    }

    
class ReferenceType
    {
        
public int Number { get; set; }
    }

In this example, the constructor had originally set ReferenceType.Number to 1. The method Change() sets ReferenceType.Number to 9. Since that ReferenceType is a reference, the memory location on the heap has been modified. Therefore, the change will be reflected in the Console.WriteLine() statement. Despite being a value type and the variable in Change() being a copy of the variable in Main(), the semantics of Test have changed to be partly mutable.

Tags:

Kodefu

Comments

6/8/2009 2:32:09 PM #

trackback

Trackback from DotNetKicks.com

More On Structs

DotNetKicks.com

6/9/2009 2:28:06 PM #

Stan

very interesting article. I never knew of the ValueType class.

Does this allow you to pass different structs without boxing and unboxing them?

Stan United States

6/10/2009 12:30:20 AM #

chris

Well, ValueType isn't a reference type so I would assume this would be the case. Unfortunately, I ran through a series of tests to verify this, but I couldn't force an int to exhibit the behaviors I would expect if it were boxed when I cast it to an object.

chris United States

6/10/2009 1:47:42 PM #

trackback

Trackback from DotNetShoutout

More On Structs

DotNetShoutout

6/11/2009 3:21:20 AM #

pingback

Pingback from blog.cwa.me.uk

Reflective Perspective - Chris Alcock  » The Morning Brew #366

blog.cwa.me.uk

6/11/2009 6:16:39 AM #

Noam Gal

Just a note - Value Types are not necceserily located on the stack. They might be in the heap if they are inside a Reference Type (A class containing an int, or a struct, will have that data written "inside" it's allocated memory)

Thanks for the article.

Noam Gal Israel

6/12/2009 6:49:10 PM #

Chris Eargle

That is correct. Thanks for the clarification, Noam.

Chris Eargle United States

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.6.0.0
Theme by Mads Kristensen

Whois KodefuGuru

Chris Eargle

Chris Eargle
.NET Community Champion

LinkedIn Twitter Technorati Facebook

MVP - Visual C#

 

INETA Community Champions
Friend of RedGate
Telerik .NET Ninja
Community blogs & blog posts

I am a #52er


World Map

RecentComments

Comment RSS

Tag cloud

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010