获取实例化 object 的代码集(带继承)

Get assembly of code that instantiated object (with inheritance)

我有一个摘要 class,它需要能够加载构成 class 的 object 的程序集中包含的文件。对于我的 class 中的每个 child,我可以使用的是 FileAssembly = Assembly.GetCallingAssembly(),但是由于它是一个人们可以扩展的库,所以我希望它能够在不需要他们这样做的情况下发生。

我现在的设置是这样的:

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();
    }
}

使用我的库的人可以在不设置 FileAssembly 的情况下创建自己的 ExternalResource,这是不可取的。如果他们从已经从 ExternalResource 继承的 class 继承,那将变得非常混乱。如何获得实例化 object 的代码集?在不对现有系统进行太多更改的情况下解决它的任何其他方法也将不胜感激!

使用调用程序集可能会让那些将 ExternalResource 相关代码移动到一个新的单独程序集中而没有意识到它具有程序集依赖性,或者想要将他们的资源移动到一个单独标识的程序集中的人感到沮丧(例如,用于本地化)。

我的建议是:

  • 向构造函数添加一个显式程序集参数,使其非常清楚地表明它正在对某些程序集执行某些操作。
  • 为方便起见,为用户提供确定调用程序集的工厂方法

如果您的所有派生类型都需要构造函数参数 string id, string file 然后是新的显式程序集参数,则您的工厂方法可以是通用的。类似于:

public static TExternalResource CreateExternalResource<TExternalResource>(string id, string file, Assembly assembly = null) where TExternalResource : ExternalResource
{

    var ResolvedAssembly = assembly ?? Assembly.GetCallingAssembly();

    return Activator.CreateInstance(typeof(TExternalResource), id, file, ResolvedAssembly) as TExternalResource;
}

您可以使用 System.Diagnostics 命名空间中的 StackTrace class:

在 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;

对 thisFrame 和 parentFrame 的引用只是为了帮助理解。我建议你实际上走上堆栈框架并更稳健地做它,而不是仅仅假设它总是你想要的框架 2(如果你有一个额外的子 class,它不会给出正确的答案) .