Home > other >  Extending Debug.Log to display the name of the variable automatically
Extending Debug.Log to display the name of the variable automatically

Time:10-20

Although I copied this problem from the Unity forum, it is also related to C#, so I'm asking if you have any solutions

I frequently want to know what's the name of variable and its value:

Debug.Log("variableName: " variableName); This might output "variableName: true"

I would like to only have to write something like this instead, as it is faster and if the name of the variable changes it will still display the correct name so I won't have to change this debug line:

DebugExt.Log(variableName); The output would be the same "variableName: true"

Suppose I have ten fields and just want to look at them temporarily and think of entering an extra field name for each field .....

How can I achieve this?

Question source page: https://forum.unity.com/threads/extending-debug-log-to-display-the-name-of-the-variable-automatically.763271/

Some related solutions: extending-debug-log: https://forum.unity.com/threads/extending-debug-log-to-display-the-name-of-the-variable-automatically.763271/

CodePudding user response:

If Unity supports C# 10, you can use this slick method:

public void LogWithName(string propertyToLog, [CallerArgumentExpression("propertyToLog")] string propertyToLogName = null)
{
    Debug.Log(propertyToLogName   ": "   propertyToLog);
}

called with LogWithName(SomeVariable);

If it doesn't support C# 10 yet, then you might be able to do this old way:

public void LogWithName(Expression<Func<string>> f)
{
    var memberExpression = (MemberExpression)f.Body;

    Console.WriteLine((f.Body as MemberExpression).Member.Name   ": "   f.Compile().Invoke());
}

called with LogWithName(() => WhatIsMyName);. I tested that in LinqPad and it compiles and runs, so hopefully it works within Unity too.

I have no idea it there is any performance hit here, FYI.

Original code from: Finding the variable name passed to a function

CodePudding user response:

Thank you John B♦ for your answer. I followed John B♦'s magic code idea to make a relatively perfect "Log" code, It has the following advantages

  1. It can hold the prefix
  2. Programmer's happiness. When printing N fields, it is no longer necessary to add text descriptions repeatedly.
  3. When N field names are modified, the manual modification description prefix does not need to be changed.
  4. Automatic separator
  5. John B♦'s answer has been optimized to support fields of type int.

Here is my code:

 public static void LogWithName(string prefixStr, params Expression<Func<object>>[] values)
        {
            //You can get a object pool for StringBuilder
            var sb = new StringBuilder();
            sb.Append(prefixStr);
            for (var i = 0; i < values.Length; i  )
            {
                sb.Append(
                    $" | {(values[i].Body is MemberExpression ? ((MemberExpression)values[i].Body).Member.Name : (((UnaryExpression)values[i].Body).Operand as MemberExpression)?.Member.Name)}:{values[i].Compile().Invoke()} |");
            }
            Debug.Log(sb);
        }

Use:

Debug.Log("TEST | iString:"   iString   " |"   " | "   "iInt:"   iInt   " |");
Debug.LogFormat("TEST | iString:{0} | | iInt:{1} |", iString, iInt);
Debug.Log($"TEST | iString:{iString} | | iInt:{iInt} |");
    
//To:
    
UnityDebugHelper.LogWithName("TEST", () => iString, () => iInt);
    
//print
// TEST | iString:asd | | iInt:1234 |

Finally: With regard to Unity, it is said that this script can be made into a Dll, so that double-clicking the log can locate the correct script calling place, instead of LogWithName. Double-click the script for locating reference:How to wrap UnityEngine.Debug.Log but keeping the line of code when clicked

  • Related