Search code examples
c#.netinheritanceassembly-resolution

Get assembly of code that instantiated object (with inheritance)


I have an abstract class that will need to be able to load files contained in the assembly that made an object of the class. What I could use is FileAssembly = Assembly.GetCallingAssembly() for every child of my class, but since it is a library that people can extend I want that to happen without requiring them to do this.

My setup right now is something along the lines of:

public abstract class ExternalResource : Resource, IDisposable
{
    public string File { get; private set; }
    protected Assembly FileAssembly { get; set; }

    protected ExternalResource(string id, string file)
        : base(id)
    {
        File = file;
    }

    //and s'more code
}

public class Sound : ExternalResource
{
    public Sound (string id, string file)
        : base(id, file)
    {
        //this is the line I want to be able to get rid of
        FileAssembly = Assembly.GetCallingAssembly();
    }
}

Someone using my library could make their own ExternalResource without setting the FileAssembly, which is not desirable. It gets really messy if they would inherit from a class that already inherits from ExternalResource. How can I get the assembly of the code instantiating the object? Any other way to work around it without too much changing to the existing system would be appreciated too!


Solution

  • You can use the StackTrace class from the System.Diagnostics namespace:

    In the constructor of your ExternalResource class:

    var stack = new StackTrace(true);
    var thisFrame = stack.GetFrame(0); // ExternalResource constructor
    var parentFrame = stack.GetFrame(1); // Sound constructor
    var grandparentFrame = stack.GetFrame(2); // This is the one!
    
    var invokingMethod = grandparentFrame.GetMethod();
    var callingAssembly = invokingMethod.Module.Assembly;
    

    The references to thisFrame and parentFrame are there simply to aid understanding. I would suggest that you actually walk up the stack frame and do it more robustly, rather than just assuming that it's always frame 2 that you want (which won't give the right answer if you have an additional subclass).