Passing parameters by reference to an asynchronous method

Very poorPoorAverageGoodExcellent (2 votes) 

Asynchrony in C# 5 is awesome, and I’ve been using it a lot since it was introduced. But there are few annoying limitations; for instance, you cannot pass parameters by reference (ref or out) to an asynchronous method. There are good reasons for that; the most obvious is that if you pass a local variable by reference, it is stored on the stack, but the current stack won’t remain available during the whole execution of the async method (only until the first await), so the location of the variable won’t exist anymore.

However, it’s pretty easy to work around that limitation : you only need to create a Ref<T> class to hold the value, and pass an instance of this class by value to the async method:

async void btnFilesStats_Click(object sender, EventArgs e)
    var count = new Ref<int>();
    var size = new Ref<ulong>();
    await GetFileStats(tbPath.Text, count, size);
    txtFileStats.Text = string.Format("{0} files ({1} bytes)", count, size);

async Task GetFileStats(string path, Ref<int> totalCount, Ref<ulong> totalSize)
    var folder = await StorageFolder.GetFolderFromPathAsync(path);
    foreach (var f in await folder.GetFilesAsync())
        totalCount.Value += 1;
        var props = await f.GetBasicPropertiesAsync();
        totalSize.Value += props.Size;
    foreach (var f in await folder.GetFoldersAsync())
        await GetFilesCountAndSize(f, totalCount, totalSize);

The Ref<T> class looks like this:

public class Ref<T>
    public Ref() { }
    public Ref(T value) { Value = value; }
    public T Value { get; set; }
    public override string ToString()
        T value = Value;
        return value == null ? "" : value.ToString();
    public static implicit operator T(Ref<T> r) { return r.Value; }
    public static implicit operator Ref<T>(T value) { return new Ref<T>(value); }

As you can see, it’s pretty straightforward. This approach can also be used in iterator blocks (i.e. yield return), that also don’t allow ref and out parameters. It also has an advantage over standard ref and out parameters: you can make the parameter optional, if for instance you’re not interested in the result (obviously, the callee must handle that case appropriately).


  1. Worawut says:

    Nice. Thanks you so much. This article help me a lot.

  2. Joshua A. Schaeffer says:


    (you don’t need Ref but your post is still solid)

    • Thomas Levesque says:

      Didn’t know about that one, thanks! But I think I’ll still use my Ref class, because:

      – its name is more intuitive IMO
      – it implements conversions to/from T, which makes it easier to manipulate
      – it overrides ToString, which makes it easier to debug

  3. Nick says:


    Just came across article and I want to thank you. This really helped me. So thanks! 🙂

    However, I want to share something that got me stuck for a while. Might be a bug on your part, or might be a wrong usage by me.

    The reference got lost when the 2nd implicit operator was used. This one:
    “public static implicit operator Ref(T value) { return new Ref(value); }”
    public partial class Form1 : Form
    private async void Form1_Load(object sender, EventArgs e)
    var message = new Ref();
    await DoStuff(message);

    private async Task DoShit(Ref message)
    await Task.Delay(500);

    //When you run the following line instead of the commented line,
    //the reference in the caller method is lost.
    message = “123”;
    //message.value = “123”;

    Hope this helps some people 😉


    • Thomas Levesque says:

      Hi Nick,

      Not a bug, but a wrong usage on your part 😉

      When you assign something to the message parameter, the change is local to the method, since it is passed by value; the caller still has a reference to the original Ref<T> instance.

  4. Adrian says:

    For the VB fans out there:

    Public Class Ref(Of t)

    Public Sub New()
    End Sub

    Public Sub New(NewValue As t)
    _Value = NewValue
    End Sub

    Public Property Value As t

    Public Overrides Function ToString() As String
    Return IIf(Value Is Nothing, “”, Value.ToString)
    End Function

    ”’ Convert a Ref(of t) to a value of type t
    ”’ This type of operator is a TYPE CONVERSION operator, which is a special kind of operator that does not involve overloading symbology (+, -, >, etc.) like normal
    ”’ operator declarations do. Instead, the CType function is used as the operator ‘symbol’ to declare the conversion, because in VB, the function CType is what we use to coerce
    ”’ an object from one type to another. This is unnecessary in C#, where type conversion is coerced using the convention: (NameOfNewType)VariableOfDifferentType
    ”’ This conversion is declared WIDENING (equivalent to IMPLICIT in c#) which indicates that the conversion cannot fail.
    Public Shared Widening Operator CType(r As Ref(Of t)) As t
    Return r.Value
    End Operator

    ”’ Convert a value of type t to a Ref(of t) containing the input value
    ”’ This operator is declared NARROWING, which indicates that there are some values r, of type t that will result in a failure.
    Public Shared Narrowing Operator CType(r As t) As Ref(Of t)
    Return New Ref(Of t)(r)
    End Operator

    End Class

  5. prigoreanu constantin says:


    it’s working…

Leave a comment