Click here to Skip to main content
14,422,431 members

C# 7 ref returns and locals

Rate this:
5.00 (8 votes)
Please Sign up or sign in to vote.
5.00 (8 votes)
15 Dec 2019CPOL
Easier direct memory access in a safe way

Table of Contents

Introduction

C# 7 introduced ref-local and ref-return functionality to allow safe direct-memory access to value variables. Before C# 7, we could do it in an unsafe code but now is available to access in a safe way. This is an example of ref-local variable taking the address of the a variable. b is behaving like an alias variable of a, note the use of ref keyword on both sides of the b initialization!

int a = 10;
ref int b = ref a;
b = 20;
Console.WriteLine("{0}", a); // display 20

I visualize the equivalent C++ code as such. b is a C++ reference. Like C++ reference, ref-local variable cannot be reassigned to another variable after initialization.

int a = 10;
int& b = a;
b = 20;
printf("%d", a); // display 20

ref-return on Value Member

For the ref-return on the property, we'll use the classes below for our example. Please note that Point is structure, therefore a value type, as opposed to the reference type like Coordinate. We can only use ref-return from reference type property because structure methods cannot ref-return its instance fields. Anyone who needs a refresher on difference between .NET reference and value types can refer to this useful link.

struct Point
{
    public int x;
    public int y;
}
    
class Coordinate
{
    private Point _Point;
    public Point Pt
    {
        set { this._Point = value; }
        get { return this._Point; }
    }
    public ref Point RefPt
    {
        get { return ref this._Point; }
    }
}

As we can see, the normal Pt property has a setter while RefPt ref-return property doesn't. The reason is due to RefPt getter directly exposing _Point for outside modification once it is ref-returned. Let's first see how Pt property is normally used.

Coordinate cd = new Coordinate();
Point pt = cd.Pt; // a copy
pt.x = 10;
pt.y = 20;
Console.WriteLine("{0},{1}", cd.Pt.x, cd.Pt.y); // display 0,0
cd.Pt = pt;
Console.WriteLine("{0},{1}", cd.Pt.x, cd.Pt.y); // display 10,20

Next, we'll see how value RefPt property is normally used.

Coordinate cd = new Coordinate();
ref Point pt = ref cd.RefPt;
pt.x = 10;
pt.y = 20;
Console.WriteLine("{0},{1}", cd.Pt.x, cd.Pt.y); // display 10,20

If the ref keyword is (accidentally) omitted from both sides of the initialization, ref-return will be instead copied to the pt variable, thus _Point shall remained unmodified.

Coordinate cd = new Coordinate();
Point pt = cd.RefPt;
pt.x = 10;
pt.y = 20;
Console.WriteLine("{0},{1}", cd.Pt.x, cd.Pt.y); // display 0,0

Assuming you can directly access/modify _Point member by changing to public accessibility. The code will be like this:

Coordinate cd = new Coordinate();
cd._Point.x = 10;
cd._Point.y = 20;
Console.WriteLine("{0},{1}", cd.Pt.x, cd.Pt.y); // display 10,20

Benchmark

We'll benchmark the ref-return against value property access and public member direct access. This shall be the benchmark code of looping 10 million Coordinate objects.

Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();

for(int i=0; i < list.Count; ++i)
{
    Point pt = list[i].Pt;
    pt.x = 10;
    pt.y = 20;
    list[i].Pt = pt;
}

stopWatch.Stop();
DisplayElapseTime("Value Return RunTime:", stopWatch.Elapsed);

Stopwatch stopWatch2 = new Stopwatch();
stopWatch2.Start();

for (int i = 0; i < list.Count; ++i)
{
    ref Point pt = ref list[i].RefPt;
    pt.x = 10;
    pt.y = 20;
}

stopWatch2.Stop();
DisplayElapseTime("Ref Return RunTime:", stopWatch2.Elapsed);

Stopwatch stopWatch3 = new Stopwatch();
stopWatch3.Start();

for(int i=0; i < list.Count; ++i)
{
    list[i]._Point.x = 10;
    list[i]._Point.y = 20;
}

stopWatch3.Stop();
DisplayElapseTime("Public Member access RunTime:", stopWatch3.Elapsed);

The benchmark result is below. ref-return performance is 50% over the traditional value return access and is 20% better than the public member access! The difference in timing is more pronounced when more fields are added to Coordinate class.

Value Return RunTime:00:00.040
Ref Return RunTime:00:00.019
Public Member access RunTime:00:00.025

Conclusion

After seeing ref-return in action, I must stress that the rules for ref-return functionality must be followed.

  • The result of a regular method return value cannot be assigned to a ref local variable. However, ref-return values can be implicitly copied into non-ref variables.
  • You cannot return a ref of a local variable because the actual memory must persist beyond the local scope to avoid invalid memory access.
  • A ref variable cannot be reassigned to a new memory location after initialization.
  • Struct methods cannot ref-return instance fields.
  • This functionality cannot be used with async methods.

This feature is most useful for the situations I described below:

  • Modifying fields in a property-exposed struct
  • Directly accessing an array location
  • Repeated access to the same memory location

Code examples are hosted at Github.

Reference

  • Writing High-Performance .NET Code, 2nd Edition by Ben Watson. A must-read book for those .NET code efficiency aficionados. I am not affiliated with Amazon, meaning I get no kickback when you buy from that link, so feel free to browse that webpage. Please note that some typos are in the ref-return code examples in the book, so when you copied the code and it fails to compile, be sure to check the official C# guide.

History

  • 16th December, 2019: First release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Shao Voon Wong
Software Developer (Senior)
Singapore Singapore
Shao Voon is from Singapore. CodeProject awarded him a MVP in recognition of his article contributions in 2019. In his spare time, he prefers to writing applications based on 3rd party libraries than rolling out his own. His interest lies primarily in computer graphics, software optimization, concurrency, security and Agile methodologies.

You can reach him by sending a message on CodeProject or at his Coding Tidbit Blog!

Comments and Discussions

 
QuestionVery Useful for Us Pin
Rameshkumar Anga18-Dec-19 20:04
MemberRameshkumar Anga18-Dec-19 20:04 
SuggestionA few suggestions Pin
qmartens17-Dec-19 3:38
Memberqmartens17-Dec-19 3:38 
GeneralMy vote of 5 Pin
Jean-Pierre Bachmann16-Dec-19 3:28
professionalJean-Pierre Bachmann16-Dec-19 3:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Tip/Trick
Posted 15 Dec 2019

Tagged as

Stats

3.6K views
85 downloads
5 bookmarked