Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Obtaining original variable name from within an extension method

We are currently working on a logging solution and have implemented an extension method call 'Log'. When writing to the log file, we would ideally like to write the original variable name (rather than the variable name used in the extension method).

What we are currently having to do for this is:

public void DoSomeWork()
{
    String testString = "Hey look I'm a string!";
    testString.Log("testString value");
}

With the extention method:

public static String Log(this String valueToStore, String name)
{
    // The logging code which uses the 'name' parameter
}

The issue here is that it becomes difficult to read on longer lines of code and looks clustered. What would be ideal is this:

public void DoSomeWork()
{
    String testString = "Hey look I'm a string!";
    testString.Log();
}

With the extension method:

public static String Log(this String valueToStore)
{
    // The logging code which is able to retrieve the 
    // value 'testString' from the 'valueToStore' value
}

Is this at all possible by using Reflection? I'm aware of the nameofoption, but that only returns the string 'valueToStore' when used in the extension method.

like image 238
Chris Wright Avatar asked Aug 03 '16 15:08

Chris Wright


People also ask

What is extension method in Python?

The extend() method adds all the elements of an iterable (list, tuple, string etc.) to the end of the list.

What is extension method how it is achieved?

Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are static methods, but they're called as if they were instance methods on the extended type.

What is extension method in Java?

In object-oriented computer programming, an extension method is a method added to an object after the original object was compiled. The modified object is often a class, a prototype or a type. Extension methods are features of some object-oriented programming languages.

Can we override extension method?

Extension methods cannot be overridden the way classes and instance methods are. They are overridden by a slight trick in how the compiler selects which extension method to use by using "closeness" of the method to the caller via namespaces.


2 Answers

Well, short answer is no. The variable names are not guaranteed to persist after compilation in unchanged form. That information would have to be somehow persisted (for example by the use of nameof()). Also, the variable name might not exist ("test".GetVarName()).

The long answer is: yes, possibly, but it's one of the most ridiculous things I've created in my life:

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

namespace Test1
{
    class Program
    {
        static void Main(string[] args)
        {
            var myVarName = "test";
            myVarName.Test();
            Console.ReadKey();
        }
    }

    static class Extensions
    {
        public static void Test(
            this string str,
            [System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
            [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
            [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0
        )
        {
            var relevantLine = File.ReadAllLines(sourceFilePath)[sourceLineNumber-1];
            var currMethodName = MethodInfo.GetCurrentMethod().Name;
            var callIndex = relevantLine.IndexOf(currMethodName + "()");
            var sb = new Stack<char>();

            for (var i = callIndex - 2; i >= 0; --i)
            {
                if (Char.IsLetterOrDigit(relevantLine[i]))
                {
                    sb.Push(relevantLine[i]);
                }
            }

            Console.WriteLine(new String(sb.ToArray()));
        }
    }
}
like image 69
Gerino Avatar answered Oct 04 '22 22:10

Gerino


You can use an Expression to achieve that, but performance-wise it may not be the best option:

public static void Log<T>(Expression<Func<T>> expr)
{
    var memberExpr = expr.Body as MemberExpression;

    if (memberExpr == null)
        return;

    var varName = memberExpr.Member.Name;
    var varData = expr.Compile()();

    // actual logging
    ...
}

Usage:

var test = "Foo";
Log(() => test);

Alternatively, if you're using C# 6.0, it can get a bit better using the nameof operator:

test.Log(nameof(test));

A better solution would be one that is leveraging the compiler abilities (specifically, the "Roslyn" compiler) and provide the member name on compile time.

like image 40
haim770 Avatar answered Oct 04 '22 21:10

haim770