Enumerable.Empty Vs Array Initialization Syntax

The following set of code showcases two most commonly used methods to generate an empty array in C#.

var array1 = Enumerable.Empty<string>();
var array3 = new string[0];

What would be the output of the above lines of code ? One might be tempted to say both returns True. However, that isn’t quite right. The output is as follows.

Enumerable Based => True
Array Based => False

The Enumerable.Empty returns the same empty array each time you request it, while the array initialization based approach, as noticed from above code, references difference array instances. That is a subtle, but significant difference. This is evident when you lookup the source code of Enumerable.Empty method in referencesource.microsoft.com

internal class EmptyEnumerable<TElement>
{
public static readonly TElement[] Instance = new TElement[0];
}

public static IEnumerable<TResult> Empty<TResult>() 
{
return EmptyEnumerable<TResult>.Instance;
}

As you can see, the Enumerable.empty uses the array approaches internally, but it is a static instance. This kind of explains the behavior.

Let’s examine further by benchmarking the performance using Benchmark.Net. For the tests, let’s create following class.

[MemoryDiagnoser]
public class BenchMarkTest
{
        [Benchmark]
        public void MethodWithEnumerable()
        {
            var array1 = Enumerable.Empty<string>();
            var array2 = Enumerable.Empty<string>();
            var output = ReferenceEquals(array1, array2);
        }

        [Benchmark]
        public void MethodWithArray()
        {
            var array1 = new string[0];
            var array2 = new string[0];
            var output = ReferenceEquals(array1, array2);
        }
}

The output is as follows

 Method  Mean Error StdDev Gen 0 Allocated
MethodWithEnumerable    11.630 ns  0.2632 ns  0.2703 ns  –   0 B
 MethodWithArray  7.258 ns  0.0905 ns  0.0756 ns   0.0152  24 B

As you can see, the though the array approach is slightly faster, it also consumes a bit more memory (understandably). Hence, it would depend on the context of the application you are developing that would decide which approach to use.

Async : IProgress and Immutability

In the previous post, we explored IProgress interface briefly and understood how it helps us in reporting progress. It seemed a perfect fit choice, with little chances of human errors. However, there are things one needs to be aware of to ensure you do not end up with unrecognizable errors.

Let’s rewrite the code in earlier post with slight modification.

async Task InvokeLongRunningMethod()
{
  Console.WriteLine("Initiating method call");
  var progress = new Progress<MessageObject>(ProgressDisplay);
  var result = await LongRunningMethod(progress);
  Console.WriteLine($"Completed executing method with result = {result}");
}


void ProgressDisplay(MessageObject update)
{
  Console.WriteLine(update.Message);
}

async Task<bool> LongRunningMethod(IProgress<MessageObject> progress)
{
  var test = new MessageObject();
  for(int i=0;i<100;i++)
  {
    if(i%10==0)
   {
     test.msg = $"In Progress : {i}%";
     progress.Report(test);
   }
  }

  return true;
}

public class MessageObject
{
       public string Message{get;set;}
}

We have created a MessageObject Class, which has been passed on as the parameter for the IProgress interface parameter type T. So how does this change the equation. Let’s run the code and watch the output first.

Initiating method call
Completed executing method with result = True
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%

As observed in the output, the progress shows 90% each time. Isn’t that strange. Well, not quite if you think a bit more. The IProgress.Report method calls are asynchronous and needn’t be quite completed at that moment. Since the object instance changes before the Report method is called again, the previous call too ends with same value. For this very reason, you need to ensure that the T parameter type is always immutable or you create a separate copy each time Report is invoked.

Reporting Progress in Async Method

Quite often you would need to provide some kind of progress from your long running asynchronous method, especially if it process multiple activities. Though there might be multiple ways to achieve it, Microsoft provides us with a simple and efficient interface IProgress, which enables us to achieve the result. Let’s hit the code straightaway.

void Main()
{
   InvokeLongRunningMethod();
}

async Task InvokeLongRunningMethod()
{
   Console.WriteLine("Initiating method call");
   var progress = new Progress<string>(ProgressDisplay);
   var result = await LongRunningMethod(progress);
   Console.WriteLine($"Completed executing method with result = {result}");
}


void ProgressDisplay(string update)
{
   Console.WriteLine(update);
}

async Task<bool> LongRunningMethod(IProgress<string> progress)
{

  for(int i=0;i<100;i++)
  {
     await Task.Delay(100);
     if(i%10==0)  progress.Report($"In Progress : {i}%");

  }
  return true;
}

The output would be

Initiating method call
In Progress : 0%
In Progress : 10%
In Progress : 20%
In Progress : 30%
In Progress : 40%
In Progress : 50%
In Progress : 60%
In Progress : 70%
In Progress : 80%
In Progress : 90%
Completed executing method with result = True