4

I am navigating through some 700K lines of code. A lot of interface implementation and DI usage. I am trying to figure out where a particular method is getting called from, hence I am trying to use [CallerMemberName].

All the examples I see on google etc are something like this:

public void TraceMessage(string message,
        [System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
        [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
        [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)

Where optional parms are used to get the info. My problem is that this method is part of an interface implementation. So, when I change the method signature the compiler is yelling at me.

Any suggestions on how to make an interface method play nice with [CallerMembername] would be greatly appreciated.

Waddaulookingat
  • 337
  • 3
  • 16
  • 1
    You will probably need to change the interface and any implementations along with it, but it's hard to tell what you mean. It would help to clarify what change you actually tried to make. – Mike Zboray Sep 20 '19 at 00:44
  • @Mike Zboray Thanks for asking. I tried adding the optional parms like the example above. I was hoping since those parms are optional the compiler won't care. Changing the interface is tricky because this means changing a crap ton of code. – Waddaulookingat Sep 20 '19 at 00:53
  • So you've got some interface method like ILogger.TraceMessage(string) and you want to know who is calling it? And let's say its implemented in Logger, you changed Logger.TraceMessage to add the optionals? – Mike Zboray Sep 20 '19 at 00:56
  • 1
    It is not clear what you're asking. Neither adding a default value to a parameter, nor adding the `[CallerMemberName]` attribute to a parameter, on a method that implements a member of some interface does not cause a compile-time error. Writing something like _"...the compiler is yelling at me"_ is not a useful problem description. It is neither precise nor accurate. If you are having trouble, post a good [mcve] that shows clearly what you've tried, explain _exactly_ what happens with that code, including the _exact_ text of any error message, and what _specifically_ you can't figure out. – Peter Duniho Sep 20 '19 at 01:32

2 Answers2

8

Had a similar issue - found that I could add CallerMemberName to an interface method as follows. It does change the signature for the implementing class but not for calling code - if that makes sense!

If this is the method's current signature in the interface

void TraceMessage(string message);

Change as follows

void TraceMessage(string message,
    [System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
    [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
    [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);

Update the method in the class that implements the interface

public void TraceMessage(string message,
    [System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
    [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
    [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
    {
        //  Log the params
    }

This can still be called with the original signature using just the 'message' param, and the other params will still be picked up, so no need to refactor all calling code

TraceMessage("Testing");

(Add for brevity)

using System.Runtime.CompilerServices;
Michael
  • 473
  • 5
  • 12
2

You can get a caller name in a different way without changing any signatures, try this solution

using System.Diagnostics;
// Get call stack
StackTrace stackTrace = new StackTrace();

// Get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);

This solution is much slower than compile-time that you are trying to use, but it is much less intrusive.

If performance is critical and you are using DI with IoC containers, then you may check if it supports aspects, like Unity.Interception or Ninject.Extensions.Interception. You'll need to implement an aspect (interceptor) and register it in the container, here is an example with caching interceptor.

If you don't use IoC, you can still use AOP approach and add a certain aspect to the methods that you are interested in. PostSharp can do that, but it is not a free tool, here are some alternatives.

fenixil
  • 2,106
  • 7
  • 13