Koo*_*Koo 2 .net c# .net-assembly unity-game-engine
我搜索了很多有关在.NET中在运行时重新加载程序集的内容。我可以找到的唯一方法是使用另一个AppDomain。但这使事情变得非常复杂。就我而言,这几乎是不可能的,因为将在运行时加载的程序集中的类不会继承自MarshalByRefObject。我看过Unity游戏引擎。编辑器在运行时构建组件,仅使用编译的程序集。这怎么可能?
我已经使用MEF完成了此操作。我不确定这是否适合您,但效果很好。但是即使使用MEF,它也有些复杂。
就我而言,我正在从特定文件夹加载所有dll。
这些是安装程序类。
public static class SandBox
{
public static AppDomain CreateSandboxDomain(string name, string path, SecurityZone zone)
{
string fullDirectory = Path.GetFullPath(path);
string cachePath = Path.Combine(fullDirectory, "ShadowCopyCache");
string pluginPath = Path.Combine(fullDirectory, "Plugins");
if (!Directory.Exists(cachePath))
Directory.CreateDirectory(cachePath);
if (!Directory.Exists(pluginPath))
Directory.CreateDirectory(pluginPath);
AppDomainSetup setup = new AppDomainSetup
{
ApplicationBase = fullDirectory,
CachePath = cachePath,
ShadowCopyDirectories = pluginPath,
ShadowCopyFiles = "true"
};
Evidence evidence = new Evidence();
evidence.AddHostEvidence(new Zone(zone));
PermissionSet permissions = SecurityManager.GetStandardSandbox(evidence);
return AppDomain.CreateDomain(name, evidence, setup, permissions);
}
}
public class Runner : MarshalByRefObject
{
private CompositionContainer _container;
private DirectoryCatalog _directoryCatalog;
private readonly AggregateCatalog _catalog = new AggregateCatalog();
public bool CanExport<T>()
{
T result = _container.GetExportedValueOrDefault<T>();
return result != null;
}
public void Recompose()
{
_directoryCatalog.Refresh();
_container.ComposeParts(_directoryCatalog.Parts);
}
public void RunAction(Action codeToExecute)
{
MefBase.Container = _container;
codeToExecute.Invoke();
}
public void CreateMefContainer()
{
RegistrationBuilder regBuilder = new RegistrationBuilder();
string pluginPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
_directoryCatalog = new DirectoryCatalog(pluginPath, regBuilder);
_catalog.Catalogs.Add(_directoryCatalog);
_container = new CompositionContainer(_catalog, true);
_container.ComposeExportedValue(_container);
Console.WriteLine("exports in AppDomain {0}", AppDomain.CurrentDomain.FriendlyName);
}
}
Run Code Online (Sandbox Code Playgroud)
这是实际的代码。
AppDomain domain = SandBox.CreateSandboxDomain($"Sandbox Domain_{currentCount}", directoryName, SecurityZone.MyComputer);
foreach (FileInfo dll in currentDlls)
{
string path = Path.GetFullPath(Path.Combine(directoryName, dll.Name));
if (!File.Exists(path))
File.Copy(dll.FullName, Path.Combine(directoryName, dll.Name), true);
domain.Load(typeof(Runner).Assembly.FullName);
}
Run Code Online (Sandbox Code Playgroud)
您可以通过执行此操作来重新获得域。
Runner runner = (Runner) domain.CreateInstanceAndUnwrap(typeof(Runner).Assembly.FullName, typeof(Runner).FullName);
runner.CreateMefContainer(); // or runner.Recompose();
Run Code Online (Sandbox Code Playgroud)
您将需要像这样调用您的代码。
runner.RunAction(() =>
{
IRepository export = MefBase.Resolve<IRepository>();
export?.Get("123");
Console.WriteLine("Executing {0}", export);
});
Run Code Online (Sandbox Code Playgroud)
一般来说,您不能在同一 AppDomain 内重新加载程序集。您可以动态创建一个并加载它(它将永远位于您的 AppDomain 中),您可以加载另一个几乎但不完全相同的程序集副本,但是一旦程序集位于 AppDomain 中,它就会卡住。
想象一下,库程序集定义了 SomeType,而您的客户端代码刚刚创建了一个实例。如果卸载库,这个实例会发生什么?如果库位于另一个 AppDomain 中,则客户端将使用具有明确定义(在 MarshalByRefObject 中)行为的代理(在域卸载时变得僵尸并永远抛出异常)。支持卸载任意类型将使运行时变得异常复杂、不可预测或两者兼而有之。
至于Unity,请参阅此讨论。引用:
“程序集重新加载”听起来像是某种快速更新检查,但实际上整个脚本环境都会重新加载。这将摧毁管理土地上的一切。Unity 可以通过使用其序列化系统来恢复。Unity 在重新加载之前序列化整个场景,然后重新创建所有内容并反序列化整个场景。当然,只有可以序列化的东西才能在这个过程中“生存”。
| 归档时间: |
|
| 查看次数: |
2770 次 |
| 最近记录: |