简体   繁体   中英

Does a C# class know what file instantiated it?

Is it possible to tell what file instantiated a class in C#?

For example, If I had Page1.cs and Page2.cs could a constructor in myclass.cs know what page created an object from it?

You can do this via the " Caller Information " attributes. Essentially you create some extra optional parameters on your class' constructor, apply some special attributes to them, and the compiler will fill in the details for you automatically. For example:

using System.Runtime.CompilerServices;

public MyClass
{
    public MyClass(  
    [CallerMemberName] string memberName = "",  
    [CallerFilePath] string sourceFilePath = "",  
    [CallerLineNumber] int sourceLineNumber = 0)  
    {
        ...
    }
}

You just need to call it as:

var instance = new MyClass();

and the compiler will fill in the caller's member name, file path and line number automatically.

A class can learn what class instantiated it by inspecting the stack trace during construction. So for example if you were to add this to your class' constructor:

var creator = new StackTrace().GetFrame(1).GetMethod().DeclaringType.FullName;

...you'd learn the location of the code that called new . Location as in the name of the class. You can of course inspect the declaring type's properties to learn the assembly name, location, etc.

Just bear in mind that you'd have to walk the stack frame a bit further if you have chained constructors. Also, this won't work for any object that was created through deserialization.

SOLUTION 1 (requires .NET 4.5 and editing your code )

Suppose that this is Caller.cs

public class Caller
{
    public Caller()
    {
        new Callee();
    }
}

and this is Callee (the class that will be called):

using System.Runtime.CompilerServices;
...

public class Callee
{
    public Callee([CallerFilePath] string callerFileName = "")
    {
        Console.WriteLine(callerFileName);
    }
}

The output will be

c:\users\francesco\source\repos\ConsoleApp19\ConsoleApp19\Caller.cs

A longer explanation is eg here ; [CallerFilePath] will take care of retrieving the caller file name and store it in the callerFileName parameter of the constructor of Callee . This requires editing your source code and at least .NET 4.5 , which I'm not sure is a requirement every application will satisfy.


SOLUTION 2 (requires just editing your code )

So, you can just change the constructor of Callee to pass it a string parameter, which will be the name of your Caller (eg "Caller.cs" ):

 public class Caller { public Caller() { new Callee("Caller.cs"); } } public class Callee { public Callee(string callerFileName = "") { Console.WriteLine(callerFileName ); } } 

Which of course will be a viable solution if you just have a few classes ( Caller being one of them) and will work with every version of the .NET framework.

Anyway it's not recommended to use a file to host several classes, but it might have been done by someone else in legacy code: so you can get the file name but still not the calling class, which is why you can use the method I just listed (directly passing the name of the caller to the constructor) instead of the first.


SOLUTION 3 (requires no code edits )

Last but not least, if you are just debugging from Visual Studio, you don't have to do any of the above: just use StackFrame: set a breakpoint to the constructor of Callee and click on the StackFrame dropdown:

StackFrame下拉菜单

This will require no code editing whatsoever, and clearly shows that the constructor of Callee is called by Caller ; you can just click on any line of the menu and you will be brought to the calling line.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM