我有一个抽象类,它需要能够加载制作该类对象的程序集中包含的文件。我可以使用的是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的情况下创建自己的外部资源,这是不可取的。如果他们从已经从外部资源继承的类继承,那会变得非常混乱。如何获取实例化对象的代码程序集?在不对现有系统进行太多更改的情况下解决它的任何其他方法也将不胜感激!
您可以使用 System.Diagnostics 命名空间中的 StackTrace 类:
在 ExternalResource 类的构造函数中:
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 帧(如果你有一个额外的子类,它不会给出正确的答案)。
使用调用程序集可能会让将来将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;
}