DEV Community

Bruce Axtens
Bruce Axtens

Posted on • Edited on

Who am I? Me, the name of the currently executing method in C# (Part 2)

It seems that thinking about Me all the time is problematic outside of personal relationships as well as within them. In part 1 I discussed my JavaScript and C# implementation of Me.

A couple of exceptionally helpful people have pointed out that my approach is rather expensive in terms of run-time speed. Being curious (and desiring to be distracted), I cooked up a quick benchmark of the two approaches (mine and the one suggested by Matt Eland).

The benchmarking code is derived from a Stackoverflow solution provided by one Alex Erygin.

First the benchmarking code:

using System;
using System.Diagnostics;

namespace dotnets
{
    public class Benchmark : IDisposable
    {
        private readonly Stopwatch timer = new Stopwatch();
        private readonly string benchmarkName;

        public Benchmark(string benchmarkName)
        {
            this.benchmarkName = benchmarkName;
            timer.Start();
        }

        public void Dispose()
        {
            timer.Stop();
            Console.WriteLine($"{benchmarkName} {timer.Elapsed}");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Then the Main

using System;
using System.Diagnostics;

namespace dotnets
{
    class Program
    {
        private static string Me => new StackTrace().GetFrame(1).GetMethod().Name;

        static void Main(string[] args)
        {
            using (var bench = new Benchmark("Using Me"))  {
                for(var i = 0; i < 1000; i++) foo1();
            }
            using (var bench = new Benchmark("Using nameof"))  {
                for(var i = 0; i < 1000; i++) foo2();
            }
        }

        static string foo1()
        {
            var me = Me;
            return me;
        }
        static string foo2()
        {
            var me = nameof(foo2);
            return me;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Then a copy of a Debug run

>dotnet run
Using Me 00:00:00.0122772
Using nameof 00:00:00.0001258
Enter fullscreen mode Exit fullscreen mode

and a Release run

>dotnet run -c Release
Using Me 00:00:00.0164321
Using nameof 00:00:00.0000010
Enter fullscreen mode Exit fullscreen mode

nameof being resolved at compile-time is clearly the winner. So if run-time speed is an issue for you, use nameof.

Top comments (3)

Collapse
 
katnel20 profile image
Katie Nelson

Thanks Bruce. I learn something new everyday!
As a suggestion for a future topic: the Dispose pattern used in .NET (I'm confused on whether it takes a bool or not).

Collapse
 
bugmagnet profile image
Bruce Axtens • Edited

I'm intrigued by Erygin's Dispose pattern too. What he is doing is following C#'s Destructor pattern rather than its Finalizer pattern. See Implementing IDisposable and the Dispose Pattern Properly.

It would be interesting to discover whether a Finalizer would work in the same way for a using block as is done in the Benchmark object.

As for the Dispose taking a second parameter, that is mentioned in the Microsoft documentation Implementing a Dispose method which says

The Dispose(Boolean) overload

In the second overload, the disposing parameter is a Boolean that indicates whether the method call comes from a Dispose method (its value is true) or from a finalizer (its value is false).

The Destructor pattern examples I've seen so far don't use this overload. However, the CodeProject article goes into a lot of detail and does discuss the second form thoroughly.

Collapse
 
katnel20 profile image
Katie Nelson

I looked at that CodeProject article as you suggested. It's very detailed and will take me some time to fully digest. The Microsoft doc seems to be a little more precise. I'm just surprised that to use Dispose correctly, you have to keep track it's usage with your own flag. Seems like old school programming. Whenever I use flags in my stuff, our coding advisor always makes a face!

Thanks again for the information. I'll be sure to use it.