GarretGarner
GarretGarner

Reputation: 13

Automatically passing own type to function call

I'd like to pass a value when calling a function but want to omit to actually add it as a parameter.

To be more precise I'd like to write a logger that also prints which class called the logging function but don't want to always pass a "this" as a parameter.

Example code:

class static Logger{
    public static void LogMsg(string msg, object objectCalling){
         Print(objectCalling.GetType().Name + ": " + msg);
    }
    private void Print(string msg){
        // print it
    } 
}

class SomeClass{
    private void WriteTestLog() {
        Logger.LogMsg("Testing!");
    }
}

This should then create an output like: "SomeClass: Testing!"

I am not sure how to tackle this maybe I am just missing sth.

Upvotes: 1

Views: 1436

Answers (4)

György Kőszeg
György Kőszeg

Reputation: 18013

If you really wish to extract the caller's type you can play with the stack trace:

[MethodImpl(MethodImplOptions.NoInlining)]
public static void LogMsg(string msg)
{
     var caller = new StackTrace().GetFrames()[1].GetMethod();
     Console.WriteLine($"{caller.DeclaringType}.{caller.Name}: {msg}");
}

But keep in mind that extracting the caller from the stack trace is a very expensive operation. Besides despite of the NoInlining it is not guaranteed that in an optimized build the caller itself is not inlined. I do not recommend to use it in a release build or if performance matters.

Upvotes: 0

PaulF
PaulF

Reputation: 6773

You could create an extension method to do that as well as the answers above :

void Main()
{
SomeClass x = new SomeClass();
x.WriteTestLog();

int i = 1;
i.LogMsg("abc");
}

public static class Logger
{
  public static void LogMsg(this object objectCalling, string msg)
  {
      Print(objectCalling.GetType().Name + ": " + msg);
  }
  private static void Print(string msg)
  {
    Console.WriteLine(msg);  // print it
  } 
}

public class SomeClass
{
  public void WriteTestLog()
  {
    this.LogMsg("Testing!");
  }
}

Upvotes: 0

Samvel Petrosov
Samvel Petrosov

Reputation: 7706

You can use System.Runtime.CompilerServices with it's CallerMemberNameAttribute

Here is example:

using System;
using System.Runtime.CompilerServices;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            Logger.WriteLog("Hello");
        }

    }
    public class Logger
    {
        public static void WriteLog(string msg, [CallerMemberName] string methodName="")
        {
            Console.WriteLine("Method:{0}, Message: {1}",methodName,msg);
        }
    }
}

Upvotes: 2

Patrick Hofman
Patrick Hofman

Reputation: 156948

There are a few attributes which might be helpful:

  • CallerMemberNameAttribute: the name of the calling method or property;
  • CallerFilePathAttribute: the file path where the calling member is in;
  • CallerLineNumberAttribute: the line number within the file.

As you see, there is no attribute for the class name, but with the file path you might achieve the same level of information.

How to use this? Decorate an argument in your logging method with the attribute (of course, using the correct type and default).

public static void LogMsg(string msg, [CallerMemberName] string callingMember = null)
{
     Print($"{callingMember}: {msg}");
}

And just call:

LogMsg("hello!");

Upvotes: 2

Related Questions