I couldn't figure out how to formulate the title any better. I see quite a few posts with similar titles but which discuss entirely different stuff.
So here we go. The actual on-ground situation is complex, but I'll try to post an absolute minimalistic example to describe it.
Let's say we have a class named Animal
:
class Animal
{
public void Run()
{
try
{
//try running
}
catch(Exception e)
{
MessageBox.Show(this.SomeCleverWayOfGettingPropertyName() " failed to run");
}
}
}
Now I define several properties of Animal
type in another class:
class Zoo
{
public Animal Zebra {get; set;}
public Animal Lion {get; set;}
public Animal Rhino {get; set;}
public void RunAll()
{
Zebra.Run();
Lion.Run();
Rhino.Run();
}
}
What do I write in place of SomeCleverWayOfGettingPropertyName()
to let it show name of the animal (that is name of the declared property), like "Zebra failed to run".
As I said, the actual situation is more complex, so kindly avoid answers like, "why don't you redesign your entire code base and instead try X". My hope is to find something in System.Reflection
to find out the calling member's name, but I haven't found anything like that yet.
CodePudding user response:
Ideally you would rethink your problem, and possibly catch outside of the run
Depending on your exact needs, an expression might work.. However it really is a terrible solution, if you went to all the effort you might as well catch outside, or just pass the member name in.
Given
public class Animal
{
public void Run()
{
Console.WriteLine("Running");
}
}
public static class MemberInfoGetting
{
public static void Run<T>(this Expression<Func<T>> memberExpression) where T : Animal
{
var expressionBody = (MemberExpression)memberExpression.Body;
try
{
var animal = Expression.Lambda<Func<Animal>>(expressionBody).Compile()();
animal.Run();
throw new Exception("bob");
}
catch
{
Console.WriteLine($"{expressionBody.Member.Name} : failed to run");
}
}
}
Usage
public static Animal Rhino { get; set; } = new Animal();
public static void Main()
{
MemberInfoGetting.Run(() => Rhino);
}
Output
Running
Rhino : failed to run
CodePudding user response:
you can try this:
class Animal
{
public void Run([CallerMemberName] string caller = null)
{
try
{
//try running
}
catch(Exception e)
{
MessageBox.Show(caller " failed to run");
}
}
}
CodePudding user response:
This is basically not possible with this approach. What happens when you call Zebra.Run()
:
- Runtime calls the auto-generated
get_Zebra()
method, putting the Zebra's Animal instance pointer on the stack. - Runtime calls the
Animal.Run()
instance method.
All variable/property info about where that instance came from is pretty much gone at that point.
Now Animal.Run()
doesn't know it's being called on an instance that came from a property, and there's no guarantee it will be. It could as well be a local, a method parameter or a new()
ed instance, one from a factory or a collection element. You'll have to pass this info yourself.
Alternatively, if it's for error handling, it may be easier than you think without having to resolve to compiler magic or expensive expression refactoring:
In your exception handler, log the relevant properties that identify the Animal instance. Combined with the stack trace, this should give you enough information.