Expand Caller Info Attributes

Topics: C# Language Design, VB Language Design
Apr 18, 2014 at 2:55 PM
The current batch of caller info attributes supported in C# 5.0 and VB.NET 12 provide only limited information as to the calling member. Only the name of the member is available which does not differentiate it from overloads or similarly named members in other classes. For the purposes of more thorough tracing I would like to see a few additional caller info attributes added:
// The name of the declaring type of the calling member.
[CallerMemberTypeName] string typeName = ""
// The namespace of the declaring type of the calling member.
[CallerMemberNamespaceName] string namespaceName = ""
// The full type name of the declaring type of the calling member.
[CallerMemberTypeFullName] string typeName = ""
// The declaring type of the calling member.
[CallerMemberType] Type type = null
// The MethodBase representing the calling member.
[CallerMember] MethodBase method = null
For the last attribute the compiler would emit the following IL in order to obtain the method, which is the method equivalent to typeof(T):
ldtoken _CurrentMethod_
call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
UserVoice #1
UserVoice #2
Apr 19, 2014 at 8:48 AM
+1, I will also need that
Developer
Apr 21, 2014 at 11:47 PM
Could you please tell us for each of these why you would like them and how you would use them?
Apr 22, 2014 at 1:54 AM
nmgafter wrote:
Could you please tell us for each of these why you would like them and how you would use them?
Honestly the only three I would likely use would be the existing CallerFilePathAttribute and CallerLineNumberAttribute combined with the proposed CallerMemberAttribute. The reason is that the tracing library that my company uses stores the member information from the MethodBase of the calling method which it obtains currently by grabbing the StackTrace. From that method base the full type name, method name and signature are written into the trace log along with the message.

I'd love to cut over to using caller info attributes rather than StackTrace but without at least the type name it doesn't fit the bill and anything less than a MethodBase from which we can format the type and member names would be a regression in functionality.

The C++ bindings to the same tracing library relies on macros which include __FILE__, __LINE__ and __FUNCSIG__.
Apr 22, 2014 at 7:53 AM
Edited Apr 22, 2014 at 8:21 AM
For me the missing type is CallerMemberTypeName or CallerMemberType. I would like to make extensible enums in readonly static fields without repeating the member name and declaring type:

Imagine Color is a extensible enum, much like ConsoleColor but other libraries could add new values.
public static class GreenForestColors
{
      public static readonly Color DarkGreen = new Color("DarkGreen", typeof(GreenForestColors));
      public static readonly Color LightGreen = new Color("LightGreen", typeof(GreenForestColors));
      public static readonly Color BrownGreen = new Color("BrownGreen", typeof(GreenForestColors));
}
The declaring type is necessary to disambiguate between libraries (or modules) that have chosen the exact same member name, but I would like to write:
public static class GreenForestColors
{
      public static readonly Color DarkGreen = new Color();
      public static readonly Color LightGreen = new Color();
      public static readonly Color BrownGreen = new Color();
}
Right now I'm being able to implement it using CallerMemberName, StackFrame and [MethodImpl(MethodImplOptions.NoInlining)], but if the compiler could do it will be faster.

NLog also needs the declaring type: LogManager.GetCurrentClassLogger();
May 4, 2014 at 8:17 PM
Poking around in the source I do see how the Caller Info attributes are implemented on top of default parameter values, so I can see how supporting more than primitives might be complicated. I started to mess with just replacing how CallerMemberAttribute functions to see what information I could work with and there is already some amazing detail readily available through the different ways to format display strings for a particular symbol. For example, the TestFormat would nearly perfectly allow for a caller attribute similar to __FUNCSIG__.

So if I were to potentially approach implementing another caller info attribute how does that get coordinated with the development team? I understand that the effort of writing the appropriate validation and comprehensive tests would fall on my shoulders but I imagine that there are controls around warning and error numbers and messages. That's assuming that the development team is actually entertaining pull requests at all at this time.
May 17, 2014 at 1:18 AM
I believe the last form would be the most useful. If we could get the MethodBase passed in, surely we would be able to extract the calling member type from that.
We could also differentiate between overloads with that, which is a big bonus. Of course extracting things like namespace and type name would not be compile time as the other attributes you propose, but I feel it would be an acceptable trade off in almost all cases.
As a side note, it would work with obfuscation too.
Mar 23, 2015 at 12:11 PM
Edited Mar 23, 2015 at 12:13 PM
Also a [FromClass] for Attributes is important.

Example:
  Public Class MyClaseBase{
     internal static void Register(Type type=null){...}
     public static MyClaseBase Factory(....){...}
   .....
  }
  
  [Factory()]
  Public Class Clase1:MyClaseBase{ 
    Internal Clase1(...){...}
    ...
  }
  
  Public Class FactoryAttribute:Attribute{
       Public FactoryAttribute([FromClass] Type type=null){...}
  }
Mar 23, 2015 at 1:04 PM
Note that all discussions have moved over to Github. I reposted this thread here.