Currently I have the function CreateLog() for creating a a log4net Log with name after the constructing instance\'s class. Typically used as in:
class MessageRe
Normally, MethodBase.ReflectedType would have your info. But, according to MSDN StackFrame.GetMethod:
The method that is currently executing may be inherited from a base class, although it is called in a derived class. In this case, the ReflectedType property of the MethodBase object that is returned by GetMethod identifies the base class, not the derived class.
which means you're probably out of luck.
Walk up the stack checking for base class - derived class relationship.
var type = new StackFrame(1).GetMethod().DeclaringType;
foreach (var frame in new StackTrace(2).GetFrames())
if (type != frame.GetMethod().DeclaringType.BaseType)
break;
else
type = frame.GetMethod().DeclaringType;
return CreateLogWithName(type.FullName);
You may want to put in a check that the methods examined are constructors. But a scenario where the subclass is instantiating the superclass in a method other than it's constructor, may still want the current behaviour.
Try the StackTrace.GetFrames method. It returns an array of all the StackFrame objects in the call stack. Your caller should be at index one.
class Program
{
static void Main(string[] args)
{
Logger logger = new Logger();
Caller caller = new Caller();
caller.FirstMethod(logger);
caller.SecondMethod(logger);
}
}
public class Caller
{
public void FirstMethod(Logger logger)
{
Console.Out.WriteLine("first");
logger.Log();
}
public void SecondMethod(Logger logger)
{
Console.Out.WriteLine("second");
logger.Log();
}
}
public class Logger
{
public void Log()
{
StackTrace trace = new StackTrace();
var frames = trace.GetFrames();
Console.Out.WriteLine(frames[1].GetMethod().Name);
}
}
this outputs
first FirstMethod second SecondMethod
I think you may be asking the wrong question. First of all the logger should be static to each class - each class should declare its own logger (to ensure that class names are properly reported AND to allow selective reporting of log messages filtered by project or namespace, from the config file.
Secondly it appears that you have created this method solely to identify the name of the calling class? If so we use this boilerplate code that is pasted into each class:
private static ILog log =
log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
Because it is private you ensure that your inheriting classes must declare their own logger and not use yours. Because it is static you ensure that the overhead of looking up the logger is only incurred once.
My apologies if you had different reasons for coding the Util.CreateLog() method.
Is there anyone who can show me how to implement a zero argument CreateLog() that gets the name from the subclass and not the declaring class?
I don't think you'll be able to do it by looking at the stack frame.
While your class is IMReceiver
, the call to CreateLog
method is in the MessageReceiver
class. The stack frame must tell you where the method is being called from, or it wouldn't be any use, so it's always going to say MessageReceiver
If you called CreateLog
explicitly in your IMReceiver
and other classes, then it works, as the stack frame shows the method being called in the derived class (because it actually is).
Here's the best thing I can come up with:
class BaseClass{
public Log log = Utils.CreateLog();
}
class DerivedClass : BaseClass {
public DerivedClass() {
log = Utils.CreateLog();
}
}
If we trace creation of logs, we get this:
new BaseClass();
# Log created for BaseClass
new DerivedClass();
# Log created for BaseClass
# Log created for DerivedClass
The second 'log created for derived class' overwrites the instance variable, so your code will behave correctly, you'll just be creating a BaseClass log which immediately gets thrown away. This seems hacky and bad to me, I'd just go with specifying the type parameter in the constructor or using a generic.
IMHO specifying the type is cleaner than poking around in the stack frame anyway
If you can get it without looking at the stack frame, your options expand considerably