- Home /
Generic Debug Message
So, this has been bugging me for awhile now and altough this isnt something crucial, it would save me sometime.
From time to time I have to create a Debug message to.... well, debug. And every message I create has the same format:
Lets say I have a variable called assetPathAndName, which is a string and holds the message "Assets/". So my Debug.Log will be like this:
Debug.Log( "assetPathAndName: " + assetPathAndName );
Which will have the following output: "assetPathAndName: Assets/". (without the quotes)
How would I create a method which would only have a generic parameter (basically the types that Debug.Log supports, int, float, Vector3, string...) and would create a string containing both the variable name and the variable value?
Thanks!
I don't believe it's possible to use reflection to get a variable name since it no longer exists once it's compiled to IL. There are some ways to get it it seems, but I don't know how cross platform it is.
Exectly. With reflection alone it's almost impossible. Afaik Unity's $$anonymous$$ono version doesn't support expression trees. Reflection works on types only. If you pass a variable to a generic method two things happens:
The compiler inferres the generic type from the variable's type. For example "int" (or "string" in your case).
When you call the method you don't pass a variable to the method but it's value. The variables name isn't passed.
Even when you would analyse the compiled IL code (isn't possible in webbuilds afaik) there are two different cases:
You pass a local variable
You pass a member variable of a class.
In the first case the compiled code doesn't have any variable name. Local variables inside a method don't have names. They just have an index on the local stack.
In the second case the actual member can be deter$$anonymous$$ed, but for this you would have to literally analyse each opcode in all methods to find the places where your method get called and analyse it's parameter.
This is far to complicated for a debug library. However if you want a link to play with, here it is.
Actually, although not as generic as Id want to, the link @Dave Carlile sent contained the answer:
public static string GetParameterInfo1<T>( T item ) where T : class
{
if( item == null )
return string.Empty;
var param = item.ToString( ).TrimStart( '{' ).TrimEnd( '}' ).Split( '=' );
return "Parameter: '" + param[ 0 ].Trim( ) +
"' = " + param[ 1 ].Trim( );
}
The downside is that the call actually takes longer to write than what a regular Debug.Log call would (or maybe instantiating a class and using those brackets annoys me):
int thisIsATest= 43;
Debug.Log( GetParameterName1( new { thisIsATest} ) );
This actually prints 'thisIsATest' = 43
And the following will only prints "item: 43"
public static string GetParameterName( object item )
{
return GetParameterName1( new { item } );
}
Which I think ends up in one of @Bunny83 cases.
Couldnt figure a way to bypass the class instantiating.
Answer by thrmotta · Jul 29, 2015 at 09:21 PM
Actually, this did work (tested with int, string, a Custom Interface and Vector3):
public static void Check<T>( System.Func<T> expr )
{
// get IL code behind the delegate
var il = expr.Method.GetMethodBody( ).GetILAsByteArray( );
// bytes 2-6 represent the field handle
var fieldHandle = System.BitConverter.ToInt32( il, 2 );
// resolve the handle
var field = expr.Target.GetType( )
.Module.ResolveField( fieldHandle );
Debug.Log( "Name is: " + field.Name );
Debug.Log( "Value is: " + expr( ) );
}
Got it from this link
Thanks @Bunny83 and @Dave Carlile for point me to the right link! =)
Well, the IL parsing approach also requires you to create a class instance (the lambda delegate). Also "GetILAsByteArray" creates a byte array. Both not ideal for the GC.
Also be careful with that approach. You don't look at the actual opcode at all. You just assume that byte 2-6 are an integer that represents a field token id. If that's not the case ResolveField might fail and throw an exception or return complete nonsense.
True! I tried to use that method with Application.DataPath and it threw me an exception, now I understand why. Thanks :)
After all Ill just stick with the regular Debug.Log. Better to waist a second longer on typing than to wait for unity to build and throw me an exception.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Not able to convert GetComponent ().netId to a string. 0 Answers
debugging multiple gameobjects with the same script 0 Answers
C# Generic return type 1 Answer