Deep C# - Value And Reference
Written by Mike James   
Monday, 04 October 2021
Article Index
Deep C# - Value And Reference
Heap and Stack
Lifetimes

Value and reference are a fundamental division in the way C# treats data. It is important that you understand the differences and, most importantly, when to use a struct and when to use a class. These aren't just differences in efficiency, they affect the semantics too. Find out in this extract from my new book, Deep C#:Dive Into Modern C#.

Deep C#

 Buy Now From Amazon

DeepCsharp360

 Chapter List

  1. Why C#?
    I Strong Typing & Type Safety
  2. Strong Typing
       Extract 
    Why Strong Typing
  3. Value & Reference
  4.    Extract Value And Reference
  5. Structs & Classes
       Extract
    Structs & Classes 
  6. Inheritance
      
    Extract
    Inheritance
  7. Interfaces & Multiple Inheritance
      
    Extract Interface
  8. Controlling Inheritance
    II Casting & Generics
  9. Casting - The Escape From Strong Typing
      
    Extract Casting I
  10. Generics
  11. Advanced Generics
  12. Anonymous & Dynamic
    Typing
    III Functions
  13. Delegates
  14. Multicast Delegates
  15. Anonymous Methods, Lambdas & Closures
    IV Async
  16. Threading, Tasks & Locking
  17. The Invoke Pattern
  18. Async Await
  19. The Parallel For ***NEW!
    V Data - LINQ, XML & Regular Expressions
  20. The LINQ Principle
  21. XML
  22. LINQ To XML
  23. Regular Expressions
    VI Unsafe & Interop
  24. Interop
  25. COM
  26. Custom Attributes
  27. Bit Manipulation
  28. Advanced Structs
  29. Pointers 

Extra Material

 <ASIN:1871962714>

 <ASIN:B09FTLPTP9>

Value and reference are a fundamental division in the way C# treats data. It is important that you understand the differences and most importantly when to use a struct and when to use a class. These aren't just differences in efficiency, they affect the semantics too.

Value and Reference

As already discussed, see Chapter 2, C# is an object-oriented, strongly typed language. The “object-oriented” part of the definition simply means that, in principle at least, everything is derived from the object class. However, all object-oriented languages suffer from the need to treat some types of very simple values as something other than objects. The reason for this is mostly efficiency – do you really want to wrap a simple integer value in all the machinery needed to implement a full class? But there is also a fundamental difference in the way programmers think about simple data types and class-based types. C# tackles this distinction in a very reasonable way that combines efficiency, a natural approach and an object-oriented outlook.

Pointers Become References

C# defines two different types of variable, value and reference.

(There is also a pointer type which acts much like an untyped reference, but this needs special treatment - see Chapter 28)

A value type usually corresponds to the simplest of data types, i.e. an int or a float, and the data is stored on the stack or within the code itself. The amount of storage used by a value type depends on its exact type.

On the other hand a reference type is essentially a sophisticated pointer to the actual data and so always takes the same amount, usually eight bytes, of storage. A reference type is also stored on the stack but the object that it “points” at is allocated on the heap. You will notice the use of the terms “point” and “pointer” in connection with reference types and this isn’t strictly correct even if it is easier to say than reference and references.

Pointers are variables that generally contain the raw address of another variable. This is a very low-level concept and can cause all sorts of problems and bad practices because it leads on to uncontrolled access to the machine’s entire memory.

A reference type is a way of providing the same behavior, but in a controlled or managed way. Put simply:

references are safe - pointers are not!

However, despite all of the reservations, thinking about a reference as a sort of typed pointer does help understand how everything works and thinking about references as pointers, preferably some sort of abstract pointer which has nothing to do with an "address", is recommended - just don’t admit to it in polite company!

Before we move on it is vital that you are 100% clear that you know what stack and heap storage is.

Heap and Stack 

If you do know about heap and stack then skip to the next section.  

When you declare a new variable the compiler has to generate code that allocates sufficient memory to store the data it is to hold.

The whole subject of memory allocation is a complicated and interesting one, but every programmer should know about the two very general approaches - the stack and the heap.

Stack-based memory is a natural match for the way that variables are allocated and created by a program constructed as a set of nested method or function calls, which most are. What happens is that when a method is called all of its local variables are created on the top of the stack - creating its so-called stack frame. While the method executes it has access to only its local variables, i.e. its entire environment is limited to the data on the stack frame. Exceptions to this local-only rule are global variables and objects but these are allocated on the heap. If the method calls another method then the new method creates its stack frame on the top of the stack. In this way each new method can allocate its own local variables in its own portion of the memory allocated to the stack.



Last Updated ( Monday, 04 October 2021 )