Code Maze

  • Blazor WASM 🔥
  • ASP.NET Core Series
  • GraphQL ASP.NET Core
  • ASP.NET Core MVC Series
  • Testing ASP.NET Core Applications
  • EF Core Series
  • HttpClient with ASP.NET Core
  • Azure with ASP.NET Core
  • ASP.NET Core Identity Series
  • IdentityServer4, OAuth, OIDC Series
  • Angular with ASP.NET Core Identity
  • Blazor WebAssembly
  • .NET Collections
  • SOLID Principles in C#
  • ASP.NET Core Web API Best Practices
  • Top REST API Best Practices
  • Angular Development Best Practices
  • 10 Things You Should Avoid in Your ASP.NET Core Controllers
  • C# Back to Basics
  • C# Intermediate
  • Design Patterns in C#
  • Sorting Algorithms in C#
  • Docker Series
  • Angular Series
  • Angular Material Series
  • HTTP Series
  • .NET/C# Author
  • .NET/C# Editor
  • Our Editors
  • Leave Us a Review
  • Code Maze Reviews

Select Page

Value vs Reference Types in C# – In Depth Guide

Posted by Code Maze | Updated Date Aug 5, 2023 | 0

Value vs Reference Types in C# – In Depth Guide

In this article, we will learn about the categories of C# data types. We will deep dive into the differences between value types and reference types, what are they and what’s the behavior of each type when instantiated, compared, or assigned.

It’s important to understand that C# is a strongly-typed language. Each variable has a specific type and each type can either be a value type or a reference type.

Let’s start.

Value Types

Value types variables directly contain their data and all their types are defined using the struct keyword which makes them implicitly sealed and inherit from System.ValueType . .NET comes with several built-in value types:

  • Numeric types: int, long, float, double, decimal, short, etc
  • bool and char types
  • Date types: DateTime, DateOnly, TimeOnly, TimeSpan

Apart from the built-in value types, we can also define custom value types using the struct keyword, they can have both value types or reference types as fields or properties:

Become a patron at Patreon!

We declare a type ValueTypeRectangle using the struct keyword. It has an Area() method to compute the area using the Length and Width  properties and prints their values before returning . It also has a MyShape property that is of type Shape which is a reference type. Shape has only one Name property.

Value Type Assignment

The first behavior that is specific to value types is their assignment:

First, we create a firstRectangle object of the ValueTypeRectangle type and assign 10 to both Length and Width . Then, we declare a secondRectangle which is assigned the firstRectangle value.

After that, we change the firstRectangle ‘s Length and Width to be 20 instead of 10 and we leave secondRectangle as-is. Finally, we print the Area of both rectangles:

As a deduction, when we assign a value type to another variable, we are copying it, and the values of its value type members are copied over to the new object. When we change one of these members in either the original object or the copy, we won’t affect the members of the other one . 

Changing a Reference Type Member

When we change the Shape name in the secondRectangle from Circle to Square , then its name also changes in the original object firstRectangle .

This is because, unlike the value type members, we copy the reference to the object and we are not creating another Shape object in the memory. Both objects reference the same instance. 

In conclusion , when we assign a value type to another variable, we create a new instance of the value type, where all value type members are copied subsequentially. But only references to reference types are copied over.

Value Type Equality

Value types use memberwise comparison to determine equality. When we compare two complex value types, we are comparing the values of their fields and properties, if all of them are equal then the value types are equal to each other, regardless of their references:

Values of both firstRectangle and secondRectangle are the same, since all their respective members have the same value, despite them being two different instances of ValueTypeRectangle .

It’s worth noting that when we define a custom struct type, we can only use the Equals() method to check for equality , if we want to use the == operator then we need to overload it .

Value Type Default Value

The default value of built-in value types: 

  • bool: false
  • char: ‘\0’
  • double: 0.0
  • float: 0.0f
  • DateTime: 01/01/0001 00:00:00

Value types can’t be null unless they are declared as Nullable value types . We can also use the default operator to set the default value of each type. The default value is a new instance of the value type with all its fields or properties set to their default values.

If we didn’t define a custom parameterless constructor then the implicit default parameterless constructor also creates a value-type object with its default value. We should, however, stick to using default to avoid any surprises. 

Reference Types

Contrary to value types, reference types variables contain a reference to their data. We can think of it as a pointer to the value. C# provides several built-in reference types:

C# also allows declaring of a reference type with the help of several keywords:

Reference Type Assignment

In contrast with ValueTypeRectangle , let’s create ReferenceTypeRectangle class to understand reference types assignment:

The ReferenceTypeRectangle has a Length and Width and an Area() method that computes an area from the current value of Length and Width  properties.

Now, let’s create an instance and see how the assignment behaves:

This time we create an firstRectangle object of  ReferenceTypeRectangle class and assign 10 to both Length and Width . Then, we assign the firstRectangle to a new variable, secondRectangle .

After that, we change the Length and Width of firstRectangle to be 20 and print the Area() of both objects:

As a result, we see that both rectangles have 20 as Length and Width as well as 400 as area.

So, to conclude, when we assign a reference type variable from another one, then we are merely copying the reference over to the new variable, and we are not instantiating any new object . Hence, when we mutate the object from one variable, we mutate the other one as well, since they are two references pointing to the same object in memory. 

Reference Type Equality

When we compare two reference-type variables using the == operator or the Equals() method then the reference of both variables is compared. If both point to the same object in memory, then they are equal else they are not, this is regardless if their data is equal or not:

Both firstRectangle and secondRectangle have the same member values but they are not equal as they don’t reference the same object.

If we want to override this behavior, we can override the equality by overloading the == operator and overriding Equals() and GetHashCode() methods .

Reference Type Default Value

The default value of a reference type variable is null . If we declare a reference type variable without initializing it or if we initialize it calling default , it will have a value of null until we assign an instance to it.

Memory Allocation

In .NET, we have two kinds of memory, the stack, and the heap. All reference types are allocated in the heap , and the only allocation that happens in the stack is the allocation for the variable that holds the reference to the object in the heap. For our ReferenceTypeRectangle example:

memory allocation for value types

In the example, when we declare both the firstRectangle and secondRectangle objects as reference types, then only the space of one object is acquired in a heap and the rest are the references. And e ven though both properties are value types – int , they are allocated in the heap since they are inside a reference type ReferenceTypeRectangle .

The runtime will either store value types in the stack or in the heap, depending on where we declare them. If we declare a value type as a method or class member then it will be allocated in the stack. But if we define it as part of a reference type, or in a collection of objects like a List<int> then it will be allocated in the heap. Thi sis the case with our value-type rectangle example:

memory allocation for reference types

In our example, all the memory of both firstRectange and secondRectange is allocated in the stack, except for the MyShape property which is allocated in the heap and referenced in the stack. This is because the Shape type is a class that is a reference type.

It’s also worth mentioning that the MyShape reference for both objects is pointing to the same object in the heap, which explains why when we change the Name of the Shape from one instance of the ValueTypeRectangle  changes for the other one as well.

Value and Reference Types as Method Arguments

Value and reference types behave differently when passed as arguments to methods. When we pass a value type as an argument to the method, then we are passing a copy of it to the method.

Mutating a value-type object inside the called method does not affect the calling method value because the called and calling methods use separate copies of the value-type object.

Let’s define an IncrementRectangleLength method in the RectangleLengthIncrementer class that takes a ValueTypeRectangle and increment its length by 1:

After that, let’s call this method with an instance of ValueTypeRectangle that has 20 as a Length :

As a result, the rect.Length gets incremented to 21 inside the IncrementRectangleLength() method but its value is still 20 in the calling method.

Reference Types as Method Arguments

When we pass a reference type as an argument to a method, then we are passing a copy of its reference to the method. If we mutate the argument inside the called method then we will affect the instance of the calling method.

Let’s define an overload of  IncrementRectangleLength() method that takes a ReferenceTypeRectangle and increases its length by 1:

After that, let’s call this method with an instance of ReferenceTypeRectangle that has 20 as a Length:

As a result, the rect.Length gets incremented to 21 inside the IncrementRectangleLength()  method and the Length of the original object in the calling method is also affected to be 21.  

Performance Implications of Value and Reference Types

There can be a performance difference in the usage of value and reference types.

The runtime instantiation of value types, when they are allocated in the stack memory , is faster than the instantiation of reference types, which is done in the heap memory . On the other hand, since value types are copied over when assigned or when passed as a method argument, having big value-type objects can increase the memory footprint of our code.

Thus, we should be careful to choose between value and reference types depending on our application usage and the performance needs of our code.

Boxing and Unboxing

Boxing is the conversion of a value type to an object type. It is an implicit conversion and wraps up the value inside System.Object which is stored in a heap. Unboxing is the conversion of the object type to the value type with an explicit conversion. Both are opposite of each other:

We assign the integer number  which is a value type to boxedNumber  which is an object – a reference type. This is boxing.

Next, we are casting that boxedNumber back to the original value type int , this is called unboxing. Since the unboxing is an explicit conversion, we need to use a cast for it to work.

Boxing and unboxing are more computationally expensive than ordinary assignments, so we should be careful when using them.

Understanding the difference between value types and reference types is important for proper memory management. In this article, we explored what are reference and value types, and how to define custom ones. We also looked at how they differ from each other when instantiated, assigned, compared, and passed as an argument. We hope that this article explains the value and reference types in detail and enables you to make the right choices.

guest

Join our 20k+ community of experts and learn about our Top 16 Web API Best Practices .

  • United States
  • United Kingdom

Joydip Kanjilal

By Joydip Kanjilal , Contributor, InfoWorld |

How to use value objects in C#

Learn how you can use value objects in c# to improve the clarity, structure, and maintainability of your code..

Plastic, magnetic letters in compartmented boxes.

In the C# programming language, an object can be either a value type or a reference type. While a variable of a value type contains its value, a variable of a reference type contains a reference to an object, or a reference to an instance of the type.

The key distinction between a value type and a reference type is in the assignment semantics. Additionally, because a value type is always “copied by value,” when you pass a value type as a parameter to a method or assign it to a variable, the entire data is copied. By contrast, when you assign a reference type, only the reference is copied; both references point to the same object in the memory.

C# also lets us create what’s called value objects, a special type of object used in domain-driven design that allows us to articulate domain concepts simply, clearly, and concisely. In this article we will examine value objects, discuss their benefits, and illustrate how we can use them in C#.

Create a console application project in Visual Studio

First off, let’s create a .NET Core console application project in Visual Studio. Assuming Visual Studio 2022 is installed in your system, follow the steps outlined below to create a new .NET core console application project.

  • Launch the Visual Studio IDE.
  • Click on “Create new project.”
  • In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed.
  • Click Next.
  • In the “Configure your new project” window, specify the name and location for the new project.
  • In the “Additional information” window, choose “.NET 8.0 (Long Term Support)” as the framework version you want to use.
  • Leave the “Do not use top-level statements” and the “Enable native AOT publish” check boxes unchecked.
  • Click Create.

We’ll use this .NET 8 console application project to work with value objects in the subsequent sections of this article.

What are value objects in C#?

In the C# language, a value object is defined as an object that can be identified only by the state of its properties. Value objects represent a descriptive aspect of a domain without having an identity. In other words, value objects represent elements of the design that we care about only in terms of their contents, not their identities.

In domain-driven design (DDD), the value object pattern represents objects without identity and supports equality based on their attributes. It should be noted here that contrary to value objects, entity objects have distinct identities. Unlike entity objects, which are defined by their identity and have mutable state, value objects are defined by their attributes and are immutable.

Immutability means you cannot change a value object once it has been created; any operations performed on value objects will create a new instance instead. The immutability of value objects has important performance benefits. Because two value objects are considered equal if they contain identical values, even if they might be different objects, they become interchangeable. In other words, immutability enables object reuse.

A value objects example in C#

Consider the following class named Address, which contains a few properties and an argument constructor.

You can create an instance of this class and assign values to its properties using the following code.

However, because the Address class here exposes public setters, you could easily change the values of its properties from outside the class. This violates one of the basic features of value objects, namely its support for immutability.

We can fix this by redesigning the Address class as shown below.

As you can see above, the properties of our new Address class contain private setters, which do not allow changes to the value of any of these properties from outside the class, thereby preserving immutability. If you execute this program, you will be greeted with the error shown in Figure 1 below.

Figure 1. Value objects are immutable.

You can also implement value objects using records in C#. To do this, you use the record keyword to define a record type that encapsulates data much the same way we did with the Author class earlier. The following code snippet shows how you can define a record type in C#.

Best practices for using value objects in C#

When working with value objects in C#, you should follow these best practices:

  • Implement proper equality checks based on value to prevent inconsistencies and errors.
  • Use value objects to represent concepts in the domain model only when you feel it is appropriate.
  • Use value objects judiciously because they have performance overheads.
  • Consider implementing validation logic within your value object constructor to enforce business rules and constraints when the value object is created.
  • Adhere to recommended patterns and naming conventions to ensure clarity, consistency, and readability in your value object implementations.

Value objects encapsulate primitive types and have two main properties, i.e., they do not have an identity and they are immutable. Value objects can simplify complex data structures by encapsulating related data into a single unit. This ensures data integrity, enforces strong typing, reduces errors, and improves the readability of the source code. You can take advantage of value objects to enhance the clarity and maintainability of your C# code by providing a more expressive representation of the domain concepts.

Typically, creating value objects in C# involves overriding equality comparison and implementing appropriate value-based semantics. A typical practice involves overriding the Equals() and GetHashCode() methods, and providing other operators for comparison. Typically, we use a base class that comprises these methods that all value object implementations should extend.

In the above example, I’ve provided a basic implementation of value objects in C#. In a future post here, I’ll explore how we can implement a value object base class and discuss more advanced concepts.

Next read this:

  • Why companies are leaving the cloud
  • 5 easy ways to run an LLM locally
  • Coding with AI: Tips and best practices from developers
  • Meet Zig: The modern alternative to C
  • What is generative AI? Artificial intelligence that creates
  • The best open source software of 2023
  • Microsoft .NET
  • Development Libraries and Frameworks
  • Software Development

Joydip Kanjilal is a Microsoft MVP in ASP.NET, as well as a speaker and author of several books and articles. He has more than 20 years of experience in IT including more than 16 years in Microsoft .NET and related technologies.

Copyright © 2024 IDG Communications, Inc.

c# object assignment reference or value

Paul-Sebastian Codes

Demystifying C#'s Parameter Modifiers and Value and Reference Types

Photo by Dylan Ferreira on Unsplash

Demystifying C#'s Parameter Modifiers and Value and Reference Types

A quick and rough simplification.

Paul-Sebastian Manole's photo

13 min read

When learning C# you will find out about the different ways that variables can be passed as arguments to function parameters , such as by value or by (some kind of) reference. These are very confusing things at the beginning for people trying to learn C#. In this post, I will try to simply the concepts and summarize the otherwise very lengthy official documentation.

First of all, you need to always remember this: in C# all arguments are passed by value by default! What that means is that values are copied by default, on both variable assignments and function calls.

So, when you are not using parameter modifiers (like ref ), everything is passed by value! The difference in behavior arises from the kind of object you are passing: a value object or a reference object, and what the variables you pass contain, value objects or reference objects. So it matters that you know what kind of objects you are working with (classes, structs, records, simple types — like int, double, etc.)!

Value objects are accessed directly, sort of like they exist right there in the variable, or on the current stack. Think of them like simple types: passing them by value, which is the default, will always copy the actual data they contain.

Reference objects on the other hand are accessed via a reference, so the variable that is assigned a reference object (or a reference value) contains only a reference to the real data. Accessing that data is done transparently so the programmer doesn't have to use a different syntax for this case.

Beware that different variables can be made to hold the same value by assigning a variable to another variable. For reference types this means two variables referring to the same data:

Now obj2 contains a copy of obj1 , which holds a reference, thus the reference gets copied and the copy gets assigned to obj2 , not the actual data that obj1 points to!

In other words, obj2 and obj1 both contain two distinct references pointing to the same object in memory.

Note that reassigning obj2 does not modify obj1 , just the reference held inside that particular obj2 variable:

obj1 still holds the original MyReferenceType("1") instance after the above operation.

For value types the default behavior of passing by value is different in that the actual data gets copied.

DateTime is a value type object (a struct ) so date2 now contains a copy of the actual date1 object, not a copied reference that refers to the same object, like it happened with reference types above.

Now, if we reassign to date2 , just like before, date1 remains untouched, because we're only altering what the variable holds, nothing else:

But now , say that DateTime , which is a struct , did not have an immutable public interface, and calling AddDays did not return a new DateTime instance with a number of days added, but instead modified the state of the current instance that it's being called on:

Now, date2 would be one day ahead of date1 and date1 would be untouched, because date2 was not assigned a reference to the same data that date1 points to, but an actual copy of the data that date1 contained.

Why is that? Because DateTime is a value type (a struct). If DateTime was a reference type, adding days to date2 would have also added days to date1 because both variables would have pointed to the same data in memory.

These deductions are simple to make, once you understand what types of objects you're working with and what the default behavior of C# of passing by value means.

Parameter modifiers

The official Microsoft docs say that in C# arguments can be passed to parameters either by value or by reference , by value being the default.

Passing by reference enables function members, methods, properties, indexers, operators, and constructors to change the value of the parameters and have that change persist in the calling environment.

Functional programming advocates might not agree with the above statement, because it enables functions to change variables that are defined outside of their scope, which makes code prone to runtime bugs that are hard to diagnose.

The scope of this article is not to advocate for or against the different programming styles, but just to explain these features of the C# language and to explain when or where they might be useful.

Pass by value

The default behavior of the language, when no parameter modifiers are used, is called pass by value , like I have mentioned before.

What this means is that whatever value the variable that is passed-in holds, it will be copied from the passed-in variable to the function argument, effectively creating different instances of the data but with the same exact value (at the start, not necessarily by the end of the function block). These instances are in no other way related to each other. Changing (ie. reassigning) one does not change the other for example. They are independent.

This can sometimes be confusing for new C# programmers, because they usually think that only simple types, like int and double , are passed by value, ie. the types inheriting from ValueType , because they are cheap to copy all the time.

In fact, reference types can also be passed by value . This is what normally happens when you don't use parameter modifiers and pass a reference type to an argument. The difference between value types and reference types, is that with reference types it's the reference that gets copied from one variable to the other, not the object the variable refers to (like it happens with primitive types). This is because there's no telling how large the object graph might be and copying such objects might be very expensive to do (but if you're crazy enough, you can still implement it).

So when the copy goes through, you will have two different variables holding the same reference value, but these references, while being equal at the start, are not the same, because the variables are not the same. The variables are still independent.

Passing by value copies values , but what the value actually is underneath doesn't matter very much. C# tries to abstract away memory pointers, which are more prevalent in programming languages like C and C++. This helps you always think of variables as their values, and not as either values or references (pointers).

C# does this by automatically dereferencing pointers when you use them, without requiring any extra syntax, like you have with C++ (ie. the * prefix, the -> arrow operator, etc.).

More precisely, when a reference type object gets passed-in by value (ie. no parameter modifier is used), the outside variable's reference value gets copied to the function argument. The two variables, the outside variable and the function argument, are two distinct variables they now hold the same value: the same reference, to the same object in memory.

So if you have something like this:

It might seem like calling the function PassByValue(1, myObj1) should clone myObj1 into the function body as the object o , but that's not what happens, because myObj is not a value type, but a reference type, so what actually gets copied is the reference itself, because that is the value that is stored intrinsically in the variable.

So, while the two references ( myObj1 and o ) are two distinct variables that point to the same object in memory, nothing is preventing you from changing the value of either variable so that they no longer point to the same object (or act on the same object), but reassigning something else to the parameter variable inside the function, doesn't also reassign to the variable outside the function's scope.

To summarize, pass by value is the default behavior and it copies what the variable that's passed in holds:

  • If it's a value type object, it clones the value of the argument so that the variable in the caller's scope and the variable in the function's scope point to two different objects (but with the same value, initially).
  • If it's a reference type, it copies the reference only, so that that reference in the caller's scope (the one passed as argument) and the reference in the function's scope both point to the same same object, but while the references held by the two variables are practically one and the same, the two variables are not themselves one and the same, so reassigning one does not also reassign the other.

Pass by reference

Passing a variable by reference is very simply what it just sounds like: passing a variable, to a function, by creating a reference to the variable itself.

As you might have deduced, no matter what semantics the passed in object (via its variable) has by default (value object type or reference type), C# will always take a reference to it and pass it as argument to the function.

To elaborate:

If the variable passed in is a value type , then it will no longer be passed by value and cloned before entering the body of the function, but will actually be passed by reference like any other reference type object. C# will take a reference to the value type object (to its variable) and make the variable inside the function's scope point to the same value in memory as the variable from the calling scope.

So this is almost the same behavior like the one described above for pass by value for reference types, thus anything you do with that reference will affect the outside variable too, but this time including reassignment!

Also, because of the value semantics of value types, = (re)assigns (new) values to whatever a variable points to.

  • If the variable holds a value type, the value type is exchanged.
  • If the variable holds a reference to a reference type, the reference is exchanged.
  • If the variable holds a reference to another variable (due to the ref modified) thanks to C#'s automatic dereferencing, the value of the variable that this variable points to is actually being exchanged (😵‍💫 I know), while this variable continues to hold a reference to the other variable and its new value.

So between two variables that hold references to the same value types, if you reassign one of those variables, C# replaces the value held at the address that that variable points to. In a way, value types are also references, but they just have different semantics (and different treatment at runtime).

If the variable passed in is a reference type , then a reference to that variable will be created (a reference to a reference type), so if you reassign to that reference for example, the outside variable will reflect this change.

Note that the above two cases boil down to the same behavior: a reference to the outside variable is created and we work with that reference in the function's scope. Altering it, alters the outside variable too. Calling methods on it that might modify it, also modifies the object pointed to by the outside variable.

To conclude, value types can almost be confused with the variables that hold them, while reference types sort of sit separately from the variables that hold them and C# automatically dereferences them on access, and when using the ref modifier, new references to the arguments will be created (variables pointing to other variables, sort of like becoming aliases of them).

Here is some test code to support the ideas above:

I almost forgot, but passing by reference requires that variables be initialized when passed in (you cannot pass in null variables).

Passing by input reference

This is a special case of passing by reference where you're not allowed to modify (assign to) the variable inside the function, but you can call methods on it. Essentially the variable is readonly inside the function body (but the object is still modifiable internally via its interface).

This is good for functions that might want to take a reference to an object from an outside scope and call methods on it, but ensure that the external variable still points to the same object and that it was not swapped with another object instance, inside the function. (Might seem like a performance optimization but in most cases it's not.)

You also don't need to use the in keyword when calling the function like you do when using ref . In the calling scope, there's no need to be aware that the variable you're passing as an argument will be passed by reference, because it cannot be modified (reassigned) unexpectedly.

This also requires that the reference be already initialized before calling the function or else you'll get a null reference exception.

Passing by output reference

This is the last special case of passing by reference, which is exactly like ref but you don't need to initialize the variable before calling the function.

You do however need to assign a value to the out parameter before returning from the function.

You also need to use the out keyword when declaring and calling the function (you need to be aware of this in the calling scope because the variable is not readonly inside the function and could be reassigned).

Using out can make code more readable and can consolidate for example, multiple operations on multiple variables inside one function by having those variables be returned back to the calling scope without having to pass them as arguments, and also encapsulate them in the function's return type. This way you could use the function's return type for error reporting for example. Or you could use tuples and exceptions for error reporting.

Closing note

At this point, I mainly write these blog posts to help myself consolidate what I've learned, but I hope it can help others like myself as well. While the quality of my posts now is more of a rough draft, my focus is on learning by taking notes. I do try to keep these notes to some standard of quality though and I will try to increase the quality as time goes by.

And hey, if you have anything constructive to say or anything to ask, feel free to use the comments section below.

# Value type vs Reference type

# passing by reference using ref keyword..

(opens new window) :

In C#, arguments can be passed to parameters either by value or by reference. Passing by reference enables function members, methods, properties, indexers, operators, and constructors to change the value of the parameters and have that change persist in the calling environment. To pass a parameter by reference, use the `ref` or `out` keyword.

The difference between ref and out is that out means that the passed parameter has to be assigned before the function ends.in contrast parameters passed with ref can be changed or left unchanged.

# Changing values elsewhere

You'll notice that even though the printingList list was made before the corrections to student names after the typos, the PrintPrintingList method still prints out the corrected names:

This is because both lists hold a list of references to the same students. SO changing the underlying student object propogates to usages by either list.

Here's what the student class would look like.

# Passing by reference

If you want the Value Types vs Reference Types in methods example to work properly, use the ref keyword in your method signature for the parameter you want to pass by reference, as well as when you call the method.

Making these changes would make the number update as expected, meaning the console output for number would be 8.

# Assignment

Assigning to a variable of a List<int> does not create a copy of the List<int> . Instead, it copies the reference to the List<int> . We call types that behave this way reference types .

# Difference with method parameters ref and out

There are two possible ways to pass a value type by reference: ref and out . The difference is that by passing it with ref the value must be initialized but not when passing it with out . Using out ensures that the variable has a value after the method call:

The catch is that by using out the parameter must be initialized before leaving the method, therefore the following method is possible with ref but not with out :

This is because if condition does not hold, value goes unassigned.

# ref vs out parameters

  • Passing by reference: public void Double(ref int numberToDouble) { }

# Introduction

# value types.

Value types are the simpler of the two. Value types are often used to represent data itself. An integer, a Boolean or a point in 3D space are all examples of good value types.

Value types (structs) are declared by using the struct keyword. See the syntax section for an example of how to declare a new struct.

Generally speaking, We have 2 keywords that are used to declare value types:

  • Enumerations

# Reference types

Reference types are slightly more complex. Reference types are traditional objects in the sense of Object Oriented Programming. So, they support inheritance (and the benefits there of) and also support finalizers.

In C# generally we have this reference types:

New reference types (classes) are declared using the class keyword. For an example, see the syntax section for how to declare a new reference type.

# Major Differences

The major differences between reference types and value types can be seen below.

# Value types exist on the stack, reference types exist on the heap

This is the often mentioned difference between the two, but really, what it boils down to is that when you use a value type in C#, such as an int, the program will use that variable to refer directly to that value. If you say int mine = 0, then the variable mine refers directly to 0, which is efficient. However, reference types actually hold (as the name suggests) a reference to the underlying object, this is akin to pointers in other languages such as C++.

You might not notice the effects of this immediately, but the effects are there, are powerful and are subtle. See the example on changing reference types elsewhere for an example.

This difference is the primary reason for the following other differences, and is worth knowing.

# Value types don't change when you change them in a method, reference types do

When a value type is passed into a method as a parameter, if the method changes the value in any way, the value is not changed In contrast, passing a reference type into that same method and changing it will change the underlying object, so that other things that use that same object will have the newly changed object rather than their original value.

See the example of value types vs reference types in methods for more info.

Simply pass them into your method using the "ref" keyword, and you are then passing this object by reference. Meaning, it's the same object in memory. So modifications you make will be respected. See the example on passing by reference for an example.

# Value types cannot be null, reference types can

Pretty much as it says, you can assign null to a reference type, meaning the variable you've assigned can have no actual object assigned to it. In the case of value types, however, this is not possible. You can, however, use Nullable, to allow your value type to be nullable, if this is a requirement, though if this is something you are considering, think strongly whether a class might not be the best approach here, if it is your own type.

← IEnumerable Built-in Types →

c# object assignment reference or value

Value Type and Reference Type

In C#, these data types are categorized based on how they store their value in the memory. C# includes the following categories of data types:

  • Reference type
  • Pointer type

A data type is a value type if it holds a data value within its own memory space. It means the variables of these data types directly contain values.

tip

For example, consider integer variable int i = 100;

The system stores 100 in the memory space allocated for the variable i . The following image illustrates how 100 is stored at some hypothetical location in the memory (0x239110) for 'i':

c# object assignment reference or value

The following data types are all of value type:

Passing Value Type Variables

When you pass a value-type variable from one method to another, the system creates a separate copy of a variable in another method. If value got changed in the one method, it wouldn't affect the variable in another method.

In the above example, variable i in the Main() method remains unchanged even after we pass it to the ChangeValue() method and change it's value there.

Reference Type

Unlike value types, a reference type doesn't store its value directly. Instead, it stores the address where the value is being stored. In other words, a reference type contains a pointer to another memory location that holds the data.

For example, consider the following string variable:

string s = "Hello World!!";

The following image shows how the system allocates the memory for the above string variable.

c# object assignment reference or value

As you can see in the above image, the system selects a random location in memory (0x803200) for the variable s . The value of a variable s is 0x600000 , which is the memory address of the actual data value. Thus, reference type stores the address of the location where the actual value is stored instead of the value itself.

The followings are reference type data types:

  • Arrays (even if their elements are value types)

Passing Reference Type Variables

When you pass a reference type variable from one method to another, it doesn't create a new copy; instead, it passes the variable's address. So, If we change the value of a variable in a method, it will also be reflected in the calling method.

In the above example, we pass the Student object std1 to the ChangeReferenceType() method. Here, it actually pass the memory address of std1 . Thus, when the ChangeReferenceType() method changes StudentName , it is actually changing StudentName of std1 object, because std1 and std2 are both pointing to the same address in memory.

String is a reference type, but it is immutable. It means once we assigned a value, it cannot be changed. If we change a string value, then the compiler creates a new string object in the memory and point a variable to the new memory location. So, passing a string value to a function will create a new variable in the memory, and any change in the value in the function will not be reflected in the original value, as shown below.

The default value of a reference type variable is null when they are not initialized. Null means not refering to any object.

c# object assignment reference or value

A value type variable cannot be null because it holds value, not a memory address. C# 2.0 introduced nullable types , using which you can assign null to a value type variable or declare a value type variable without assigning a value to it.

  • How to get the sizeof a datatype in C#?
  • Difference between String and StringBuilder in C#
  • Static vs Singleton in C#
  • Difference between == and Equals() Method in C#
  • Asynchronous programming with async, await, Task in C#
  • How to loop through an enum in C#?
  • Generate Random Numbers in C#
  • Difference between Two Dates in C#
  • Convert int to enum in C#
  • BigInteger Data Type in C#
  • Convert String to Enum in C#
  • Convert an Object to JSON in C#
  • Convert JSON String to Object in C#
  • DateTime Formats in C#
  • How to convert date object to string in C#?
  • Compare strings in C#
  • How to count elements in C# array?
  • Difference between String and string in C#.
  • How to get a comma separated string from an array in C#?
  • Boxing and Unboxing in C#
  • How to convert string to int in C#?
  • More C# articles

.NET Tutorials

Database tutorials, javascript tutorials, programming tutorials.

  • C# Questions & Answers
  • C# Skill Test
  • C# Latest Articles
  • How to Pass Object by Reference in C#

Pass Variables by Value to a Function in C#

Pass variables by reference to a function in c#, pass objects by reference to a function in c#.

How to Pass Object by Reference in C#

Navigating the intricacies of passing objects to functions in C# is a fundamental aspect of programming. This tutorial dives into the methods employed for this purpose, providing insights into the nuances of passing variables by value and reference.

Understanding how these mechanisms operate is crucial, influencing the behavior of objects within functions and their impact on the original variables. We explore examples showcasing the default pass-by-value behavior, using the ref keyword to pass by reference, and the default pass-by-reference approach for reference types.

By default, C# passes parameters by value, meaning a copy of the variable is sent to the method. However, there are instances where we may want to simulate passing an object by reference using variables by value.

In this context, modifications within a method should reflect on the original object outside the method.

Consider a scenario where we have a method named method1 that attempts to modify a string passed to it. We’ll explore how this affects the original string value in the calling method.

In this code snippet, we have a Program class containing two methods: method1 and Main . The goal is to understand how the string value, initially set to Nothing , is affected when passed to method1 .

In the Main method, we declare a string variable named valueType and set its initial value to Nothing .

The method1 method takes a string parameter named value . Within this method, we attempt to modify the value of value to something .

After calling method1 in the Main method, we then display the original value of the valueType string.

We can also pass a value type variable by reference with the ref keyword in C#. The ref keyword specifies that a value is passed by reference to a function. With this approach, there will only exist one copy of the variable in the memory, and a separate pointer will be passed to the function that points to the value of the variable.

We’ll explore how using the ref keyword affects the original string value in the calling method.

In this code snippet, we have a Program class containing two methods: method1 and Main . The goal is to understand how using the ref keyword affects the original string value when passed to method1 .

The method1 method takes a string parameter named value but with the ref keyword. This signifies that we are passing the variable by reference, allowing modifications inside the method to directly affect the original variable.

Within the method1 method, we modify the value of the value parameter to something .

There are situations where you might want to pass an object by reference, allowing the method to directly manipulate the original object. This is particularly useful when dealing with large objects or when modifications should persist beyond the method’s scope.

In this section, we’ll explore how to pass an object by reference in C# using the natural behavior of reference types.

Consider a scenario where we have a Sample class with a string property. We want to understand how passing an instance of this class to a method affects the original object.

In this code snippet, we have a Sample class with a string property named s . The Program class contains two methods: dosomething and Main .

In the Main method, we create an instance of the Sample class named sam and set its s property to Nothing .

The dosomething method takes a Sample object ( obj ) as a parameter. Within this method, we display the initial value of the s property of the passed object.

Next, we create a new instance of Sample and assign a value to its s property. Finally, we display the new value of the s property.

After calling the dosomething method in the Main method, we display the original value of the s property of the sam object.

Mastering the art of passing objects to functions in C# involves grasping the subtleties of pass-by-value and pass-by-reference methodologies. The showcased examples elucidate how variables and objects behave within functions, emphasizing the critical differences between reference and value types.

Developers are equipped with the knowledge to choose the appropriate approach for their specific scenarios, ensuring effective manipulation of objects and preventing unintended consequences. Whether it’s leveraging the default behavior, employing the ref keyword for explicit pass-by-reference, or understanding the intricacies of reference types, this tutorial provides a comprehensive guide to navigating object passing in C#.

Muhammad Maisam Abbas avatar

Maisam is a highly skilled and motivated Data Scientist. He has over 4 years of experience with Python programming language. He loves solving complex problems and sharing his results on the internet.

Related Article - Csharp Class

  • Friend Class Equivalent in C#
  • How to Extend a Class in C#
  • Interface vs Abstract Classes in C#
  • How to Include a Class Into Another Class in C#
  • Nested Classes in C#
  • How to Inherit From Multiple Classes in C#

Tutlane Logo

C# Value Type and Reference Type with Examples

In c#, we have two ways to allocate the space in memory, i.e., either on stack or heap memory based on the Value Type or Reference Type parameters.

In the previous chapter, we learned about Data Types in C# and how the Data Types in c# are categorized as a Value Type or Reference Type with examples.

We will now learn the value types and reference types in c# and how the Value Type and Reference Type parameters will hold the data and memory in the same location with examples.

C# Value Types

In c#, a data type is a Value Type if it holds the value of the  variable directly on its own memory space, and Value Types will use Stack memory to store the values of the variables.

For example, if we define and assign a value to the variable like int x = 123; then the system will use the same memory space of variable ‘ x ’ to store the value ‘ 123 ’.

Following is the pictorial representation of value types in the c# programming language.

Variable Type Memory Allocation in C# with Examples

The following are the different data types that will fall under Value Type in c# programming language.

C# Pass Value Type by Value

In c#, if we pass a value type variable from one method to another method, the system will create a separate copy for the variable in another method. If we make changes to the variable in one method, it won’t affect the variable in another method.

Following is the example of passing the value type by value in c# programming language.

If you observe the above example, we defined two variables ( num1 , num2 ) in the  Main() method, and we are making changes to those variables by passing them to the  Square() method, but those changes won’t affect the variables in Main() method.

When we execute the above program, we will get the result as shown below.

C# Value Type Example Result

If you observe the above result, the changes made to variables in the  Square() method didn’t affect the variables in the  Main() method.

C# Reference types

In c#, Reference Types will contain a pointer that points to another memory location that holds the data. The Reference Types won’t store the variable value directly in its memory. Instead, it will store the memory address of the variable value to indicate where the value is being stored.

For example, if we define and assign a value to the variable like string name = "Suresh Dasari" ; then the system will store the variable value “ Suresh Dasari ” in one location and the variable " name " in another location along with the memory address of the variable value.

Following is the pictorial representation of reference type in c# programming language.

Reference Type Memory Allocation in C#

The following are the different data types that will fall under Reference Type in c# programming language.

  • All Arrays , Even if their elements are value types

Pass Reference Type by Value

In c#, if we pass a reference type variable from one method to another method, the system won’t create a separate copy for that variable. Instead, it passes the address of the variable, so if we make any changes to the variable in one method, that also reflects in another method.

Following is the example of passing the reference type by value in the c# programming language.

If you observe the above example, we created a new class called “ Person ” and created an instance of a new class ( Person ) and assigned values to the variables in Main() method, and we are making changes to those variable by passing it to Square() method and those changes will be reflected in Main() method.

When you execute the above program, you will get the result as shown below.

C# Reference Type Example Result

If you observe the above result, the changes we made to variables in the  Square() method also reflected for the variables in the  Main() method.

This is how we can use Value Type and Reference Type in c# programming language based on our requirements.

Table of Contents

  • Values Types and Reference Types in C# with Examples
  • Value Types in C# with Example
  • C# Pass Value Type By Value Example
  • Reference Types in C# with Examples
  • C# Pass Referece Type By Value Example

C# Tutorial

C# examples, c# assignment operators, assignment operators.

Assignment operators are used to assign values to variables.

In the example below, we use the assignment operator ( = ) to assign the value 10 to a variable called x :

Try it Yourself »

The addition assignment operator ( += ) adds a value to a variable:

A list of all assignment operators:

Get Certified

COLOR PICKER

colorpicker

Report Error

If you want to report an error, or if you want to make a suggestion, do not hesitate to send us an e-mail:

[email protected]

Top Tutorials

Top references, top examples, get certified.

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Type-testing operators and cast expressions - is , as , typeof and casts

  • 5 contributors

These operators and expressions perform type checking or type conversion. The is operator checks if the run-time type of an expression is compatible with a given type. The as operator explicitly converts an expression to a given type if its run-time type is compatible with that type. Cast expressions perform an explicit conversion to a target type. The typeof operator obtains the System.Type instance for a type.

is operator

The is operator checks if the run-time type of an expression result is compatible with a given type. The is operator also tests an expression result against a pattern.

The expression with the type-testing is operator has the following form

where E is an expression that returns a value and T is the name of a type or a type parameter. E can't be an anonymous method or a lambda expression.

The is operator returns true when an expression result is non-null and any of the following conditions are true:

The run-time type of an expression result is T .

The run-time type of an expression result derives from type T , implements interface T , or another implicit reference conversion exists from it to T .

The run-time type of an expression result is a nullable value type with the underlying type T and the Nullable<T>.HasValue is true .

A boxing or unboxing conversion exists from the run-time type of an expression result to type T .

The is operator doesn't consider user-defined conversions.

The following example demonstrates that the is operator returns true if the run-time type of an expression result derives from a given type, that is, there exists a reference conversion between types:

The next example shows that the is operator takes into account boxing and unboxing conversions but doesn't consider numeric conversions :

For information about C# conversions, see the Conversions chapter of the C# language specification .

Type testing with pattern matching

The is operator also tests an expression result against a pattern. The following example shows how to use a declaration pattern to check the run-time type of an expression:

For information about the supported patterns, see Patterns .

as operator

The as operator explicitly converts the result of an expression to a given reference or nullable value type. If the conversion isn't possible, the as operator returns null . Unlike a cast expression , the as operator never throws an exception.

The expression of the form

where E is an expression that returns a value and T is the name of a type or a type parameter, produces the same result as

except that E is only evaluated once.

The as operator considers only reference, nullable, boxing, and unboxing conversions. You can't use the as operator to perform a user-defined conversion. To do that, use a cast expression .

The following example demonstrates the usage of the as operator:

As the preceding example shows, you need to compare the result of the as expression with null to check if the conversion is successful. You can use the is operator both to test if the conversion succeeds and, if it succeeds, assign its result to a new variable.

Cast expression

A cast expression of the form (T)E performs an explicit conversion of the result of expression E to type T . If no explicit conversion exists from the type of E to type T , a compile-time error occurs. At run time, an explicit conversion might not succeed and a cast expression might throw an exception.

The following example demonstrates explicit numeric and reference conversions:

For information about supported explicit conversions, see the Explicit conversions section of the C# language specification . For information about how to define a custom explicit or implicit type conversion, see User-defined conversion operators .

Other usages of ()

You also use parentheses to call a method or invoke a delegate .

Other use of parentheses is to adjust the order in which to evaluate operations in an expression. For more information, see C# operators .

typeof operator

The typeof operator obtains the System.Type instance for a type. The argument to the typeof operator must be the name of a type or a type parameter, as the following example shows:

The argument mustn't be a type that requires metadata annotations. Examples include the following types:

  • string? (or any nullable reference type)

These types aren't directly represented in metadata. The types include attributes that describe the underlying type. In both cases, you can use the underlying type. Instead of dynamic , you can use object . Instead of string? , you can use string .

You can also use the typeof operator with unbound generic types. The name of an unbound generic type must contain the appropriate number of commas, which is one less than the number of type parameters. The following example shows the usage of the typeof operator with an unbound generic type:

An expression can't be an argument of the typeof operator. To get the System.Type instance for the run-time type of an expression result, use the Object.GetType method.

Type testing with the typeof operator

Use the typeof operator to check if the run-time type of the expression result exactly matches a given type. The following example demonstrates the difference between type checking done with the typeof operator and the is operator :

Operator overloadability

The is , as , and typeof operators can't be overloaded.

A user-defined type can't overload the () operator, but can define custom type conversions that can be performed by a cast expression. For more information, see User-defined conversion operators .

C# language specification

For more information, see the following sections of the C# language specification :

  • The is operator
  • The as operator
  • Cast expressions
  • The typeof operator
  • C# reference
  • C# operators and expressions
  • How to safely cast by using pattern matching and the is and as operators
  • Generics in .NET

Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see: https://aka.ms/ContentUserFeedback .

Submit and view feedback for

Additional resources

IMAGES

  1. Passing Objects by Reference or Value in C#

    c# object assignment reference or value

  2. reference

    c# object assignment reference or value

  3. Object assignment in C#

    c# object assignment reference or value

  4. Value vs Reference Types in C#

    c# object assignment reference or value

  5. C# Assignment Operator

    c# object assignment reference or value

  6. C# Value type and Reference type Explained

    c# object assignment reference or value

VIDEO

  1. 41 C# C Sharp OOP Parameterized Constructor

  2. c entity

  3. Class and Object Concept in C#

  4. Level 1 Assignment Reference : Heavy Ball Bounce

  5. Level 1 Assignment Reference: Ball Bounce in Z Space

  6. Debuging in C# Assignment 2

COMMENTS

  1. C# Reference type assignment VS value type assignment

    using System; class Employee { private string m_name; public string Name { get { return m_name; } set { m_name = value; } } } class Program { static void Main () { Employee joe = new Employee (); joe.Name = "Joe"; Employee bob = new Employee (); bob.Name = "Bob"; Console.WriteLine ("Original Employee Values:"); Console.Write...

  2. Assignment operators

    The assignment operator = assigns the value of its right-hand operand to a variable, a property, or an indexer element given by its left-hand operand. The result of an assignment expression is the value assigned to the left-hand operand.

  3. Built-in reference types

    C# has many built-in reference types. They have keywords or operators that are synonyms for a type in the .NET library. The object type The object type is an alias for System.Object in .NET. In the unified type system of C#, all types, predefined and user-defined, reference types and value types, inherit directly or indirectly from System.Object.

  4. Value vs Reference Types in C#

    We will deep dive into the differences between value types and reference types, what are they and what's the behavior of each type when instantiated, compared, or assigned. It's important to understand that C# is a strongly-typed language. Each variable has a specific type and each type can either be a value type or a reference type.

  5. Object and Collection Initializers (C# Programming Guide)

    07/14/2023 19 contributors Feedback In this article Object initializers Object Initializers with anonymous types Object Initializers with the required modifier Object Initializers with the init accessor Show 4 more C# lets you instantiate an object or collection and perform member assignments in a single statement. Object initializers

  6. What are C#'s reference and value types? · Kodify

    C# Values in C# are either of the reference or value kind. References point to a location in computer memory, while value types hold their own data.

  7. How to use value objects in C#

    In the C# programming language, an object can be either a value type or a reference type. While a variable of a value type contains its value, a variable of a reference type contains a reference ...

  8. Demystifying C#'s Parameter Modifiers and Value and Reference Types

    Reference objects on the other hand are accessed via a reference, so the variable that is assigned a reference object (or a reference value) contains only a reference to the real data. Accessing that data is done transparently so the programmer doesn't have to use a different syntax for this case.

  9. c#

    object assignment Ask Question Asked 13 years, 11 months ago Modified 4 years, 11 months ago Viewed 25k times 4 I have a scenario like: MyClass obj1 = new MyClass (); ............//some operations on obj1; MyClass obj2 = new MyClass (); obj2 = obj1;

  10. C# 9: Value Objects and Simpler Code -- Visual Studio Magazine

    C# 9: Value Objects and Simpler Code. C# 9 gives you a better way to create value objects and some simpler code to use while doing it. But even if you don't care about value objects, the new keyword has some cool changes. I won't say that, all by itself, C# 9 is worth the migration to .NET 5 (I might make that claim about C# 8 and .NET Core 3.x ...

  11. C#

    #Value type vs Reference type # Passing by reference using ref keyword. From the documentation (opens new window):. In C#, arguments can be passed to parameters either by value or by reference. Passing by reference enables function members, methods, properties, indexers, operators, and constructors to change the value of the parameters and have that change persist in the calling environment.

  12. When is a C# value/object copied and when is its reference copied

    88 I keep getting the same issue over and over again where an object I want to reference is copied or where an object I want to copy is referenced. This happens when I use the = operator. For example, if I am sending the object to another form, ie: SomeForm myForm = new SomeForm(); SomeObject myObject = new SomeObject();

  13. Value Type and Reference Type

    Null means not refering to any object. Null Reference Type. A value type variable cannot be null because it holds value, not a memory address. C# 2.0 introduced nullable types, using which you can assign null to a value type variable or declare a value type variable without assigning a value to it.

  14. ref keyword

    You use the ref keyword in the following contexts: In a method signature and in a method call, to pass an argument to a method by reference. In a method signature, to return a value to the caller by reference. For more information, see ref return.

  15. How to Pass Object by Reference in C#

    Pass Variables by Reference to a Function in C#. We can also pass a value type variable by reference with the ref keyword in C#. The ref keyword specifies that a value is passed by reference to a function. With this approach, there will only exist one copy of the variable in the memory, and a separate pointer will be passed to the function that points to the value of the variable.

  16. C# Value Type and Reference Type with Examples

    In c#, a data type is a Value Type if it holds the value of the variable directly on its own memory space, and Value Types will use Stack memory to store the values of the variables. For example, if we define and assign a value to the variable like int x = 123; then the system will use the same memory space of variable ' x ' to store the ...

  17. C# assign by reference

    2. Strings are already references, after B = A then B.equals (A) will return true. However, when you do B = "abcd" you're doing the same thing, you're assigning B to a reference to the string literal. What you are wanting to do is modify the data pointed to by the string, however, because Strings in .NET are immutable there is no way to do that.

  18. Method parameters are passed by value. Modifiers enable pass-by

    10/26/2023 13 contributors Feedback In this article Safe context of references and values Reference parameters params modifier By default, arguments in C# are passed to functions by value. That means a copy of the variable is passed to the method. For value ( struct) types, a copy of the value is passed to the method.

  19. C# Assignment Operators

    C# Assignment Operators C# Assignment Operators Previous Next Assignment Operators Assignment operators are used to assign values to variables. In the example below, we use the assignment operator ( =) to assign the value 10 to a variable called x: Example int x = 10; Try it Yourself »

  20. c#

    Assign object by reference Ask Question Asked Viewed 173 times 0 I have two viewState properties. One is a List<MyObject> MyObjects And another one is MyObject SelectedObject Whenever user selects an object from the list, I assign it to SelectedObject like this: SelectedObject = MyObjects.Where(x=>x.MyId ==IdSelectedInUI)

  21. Type-testing operators and cast expressions

    In this article. These operators and expressions perform type checking or type conversion. The is operator checks if the run-time type of an expression is compatible with a given type. The as operator explicitly converts an expression to a given type if its run-time type is compatible with that type. Cast expressions perform an explicit conversion to a target type.