什么是AppDomain?AppDomains的好处是什么?为什么微软带来了AppDomains的概念,没有AppDomains会出现什么问题?
请详细说明.
我正在为emacs中的C#完成(intellisense)工具.
这个想法是,如果用户键入片段,然后通过特定的击键组合要求完成,则完成工具将使用.NET反射来确定可能的完成.
这样做需要知道正在完成的事物的类型.如果它是一个字符串,那么有一组已知的可能方法和属性; 如果它是一个Int32,它有一个单独的集,依此类推.
使用语义,emacs中提供的代码词法分析器/解析器包,我可以找到变量声明及其类型.鉴于此,可以直接使用反射来获取类型上的方法和属性,然后向用户显示选项列表.(好吧,在 emacs中做的不是那么简单,但是使用在 emacs 中运行PowerShell进程的能力,它变得容易得多.我编写了一个自定义.NET程序集来进行反射,将其加载到powershell中,然后在内部运行elisp emacs可以通过comint向powershell发送命令并读取响应.因此,emacs可以快速获得反射结果.)
当代码var
在声明正在完成的事物中使用时,问题就会到来.这意味着未明确指定类型,并且完成将不起作用.
当使用var
关键字声明变量时,如何可靠地确定实际使用的类型?为了清楚起见,我不需要在运行时确定它.我想在"设计时"确定它.
到目前为止,我有这些想法:
我知道怎么做这一切.但对于编辑器中的每个完成请求,它听起来非常重量级.
我想我每次都不需要新的AppDomain.我可以为单个AppDomain重复使用多个临时程序集,并在多个完成请求中分摊设置和拆除它的成本.这更像是对基本理念的调整.
只需将声明编译到模块中,然后检查IL,以确定编译器推断出的实际类型.这怎么可能?我会用什么来检查IL?
还有更好的想法吗?评论?建议?
编辑 - 进一步考虑这一点,编译和调用是不可接受的,因为调用可能有副作用.因此必须排除第一种选择.
此外,我认为我不能假设.NET 4.0的存在.
更新 - 上面没有提到的正确答案,但Eric Lippert温和地指出,是实现完全保真的类型推理系统.它是在设计时可靠地确定var类型的唯一方法.但是,这也不容易.因为我苦于没有幻想,我要试图建立这样的事情,我把选项2的快捷方式-提取相关声明代码,并编译它,然后检查所产生的IL.
这实际上适用于完成方案的公平子集.
例如,假设在下面的代码片段中,?是用户要求完成的位置.这有效:
var x = "hello there";
x.?
Run Code Online (Sandbox Code Playgroud)
完成意识到x是一个String,并提供适当的选项.它通过生成并编译以下源代码来实现:
namespace N1 {
static class dmriiann5he { // randomly-generated class name
static void M1 () {
var x = "hello there";
}
}
}
Run Code Online (Sandbox Code Playgroud)
......然后用简单的反射检查IL.
这也有效:
var x …
Run Code Online (Sandbox Code Playgroud) 我想加载到一个新的AppDomain
一些具有复杂引用树的程序集(MyDll.dll - > Microsoft.Office.Interop.Excel.dll - > Microsoft.Vbe.Interop.dll - > Office.dll - > stdole.dll)
据我所知,当加载程序集时AppDomain
,它的引用不会自动加载,我必须手动加载它们.所以当我这样做时:
string dir = @"SomePath"; // different from AppDomain.CurrentDomain.BaseDirectory
string path = System.IO.Path.Combine(dir, "MyDll.dll");
AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
setup.ApplicationBase = dir;
AppDomain domain = AppDomain.CreateDomain("SomeAppDomain", null, setup);
domain.Load(AssemblyName.GetAssemblyName(path));
Run Code Online (Sandbox Code Playgroud)
得到了FileNotFoundException
:
无法加载文件或程序集"MyDll,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null"或其依赖项之一.该系统找不到指定的文件.
我认为关键部分是其依赖性之一.
好的,我之前做过 domain.Load(AssemblyName.GetAssemblyName(path));
foreach (AssemblyName refAsmName in Assembly.ReflectionOnlyLoadFrom(path).GetReferencedAssemblies())
{
domain.Load(refAsmName);
}
Run Code Online (Sandbox Code Playgroud)
但FileNotFoundException
又一次,在另一个(参考)集会上.
如何递归加载所有引用?
在加载根程序集之前是否必须创建引用树?如何在不加载程序集的情况下获取程序集的引用?
背景:Noda Time包含许多可序列化的结构.虽然我不喜欢二进制序列化,但我们收到了许多支持它的请求,回到1.x时间线.我们通过实现ISerializable
接口来支持它.
我们收到了最近一份关于Noda Time 2.x 在.NET Fiddle中失败的问题报告.使用Noda Time 1.x的相同代码工作正常.抛出的异常是这样的:
重写成员时违反了继承安全规则:'NodaTime.Duration.System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)'.覆盖方法的安全性可访问性必须与被覆盖的方法的安全性可访问性相匹配.
我把它缩小到了目标框架:1.x目标.NET 3.5(客户端配置文件); 2.x的目标是.NET 4.5.它们在支持PCL与.NET Core和项目文件结构方面存在很大差异,但看起来这是无关紧要的.
我已经设法在本地项目中重现了这一点,但我还没有找到解决方案.
在VS2017中重现的步骤:
Program.cs
.这是此Microsoft示例中代码的缩写版本.我保持所有路径相同,所以如果你想回到更完整的代码,你不应该改变其他任何东西.码:
using System;
using System.Security;
using System.Security.Permissions;
class Sandboxer : MarshalByRefObject
{
static void Main()
{
var adSetup = new AppDomainSetup();
adSetup.ApplicationBase = System.IO.Path.GetFullPath(@"..\..\..\UntrustedCode\bin\Debug");
var permSet = new PermissionSet(PermissionState.None);
permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
var fullTrustAssembly = typeof(Sandboxer).Assembly.Evidence.GetHostEvidence<System.Security.Policy.StrongName>();
var newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);
var handle = …
Run Code Online (Sandbox Code Playgroud) 特别是,在两个不同的应用程序域中运行代码的含义是什么?
数据如何通过应用程序域边界传递?是否与跨过程边界传递数据相同?我很想知道更多有关这种抽象及其有用的内容.
编辑:一般在AppDomain类的良好现有覆盖范围,我不了解应用程序域
.NET有这个应用域的概念,根据我的理解,它可用于将程序集加载到内存中.我已经对应用程序域做了一些研究,并且去了我当地的书店,了解了这个主题的一些额外知识,但它似乎非常稀少.
我所知道的我可以使用Application Domains来加载内存中的程序集,我可以在需要时卸载它们.
我提到的应用程序域的其他功能有哪些?线程是否尊重应用程序域边界?除了主要的应用程序域之外,在除了通信性能之外的不同应用程序域中加载程序集有什么缺点吗?
链接到讨论应用程序域的资源也很不错.我已经检查过MSDN,它没有那么多关于它们的信息.
我的项目设置如下:
项目"消费者"引用"定义"和"实现",但不静态引用"实现"中的任何类型.
当应用程序启动时,Project"Consumer"在"Definition"中调用静态方法,该方法需要在"Implementation"中查找类型
有没有办法可以在不知道路径或名称的情况下强制将任何引用的程序集加载到App域中,并且最好不必使用完整的IOC框架?
微软是否有理由选择不支持.NET Core中的AppDomains?
AppDomains在构建长时间运行的服务器应用程序时特别有用,我们可能希望更新服务器加载的程序集是一种优雅的方式,而无需关闭服务器.
如果没有AppDomains,我们如何在长时间运行的服务器进程中替换我们的程序集?
AppDomains还为我们提供了一种隔离服务器代码不同部分的方法.比如,自定义websocket服务器可以在主appdomain中具有套接字代码,而我们的服务在辅助appdomain中运行.
如果没有AppDomains,则无法使用上述方案.
我可以看到一个论点,可能会讨论使用VM的云概念来处理程序集更改而不必承担AppDomains的开销.但这是微软的想法或说法吗?或者他们有针对上述情况的具体原因和替代方案?
这是我最初的问题的后续内容,我想提出我的发现并要求更正,想法和见解.我的发现(或者更确切地说是解释)来自人们对我之前的问题的回答,阅读MSDN .NET 3.5文档和调试.NET 3.5代码.我希望这对那些想知道如何检测应用程序何时终止的人有价值.
事件:
System.AppDomain.CurrentDomain.ProcessExit
:当进程退出时引发,例如在默认情况下AppDomain
并且其他所有内容都被卸载[总执行时间仅限于3秒!].对于WPF,请System.Windows.Application.Exit
改用.对于Windows窗体,请Application.Run(...)
在main方法之后运行代码.
System.AppDomain.CurrentDomain.DomainUnload
:当AppDomain
默认AppDomain
卸载以外时引发,例如在运行带有单元测试框架的类时(带有TestDriven.NET的MbUnit).
System.AppDomain.CurrentDomain.UnhandledException
:(如果在默认情况下处理AppDomain
:)为任何线程中的任何未处理的异常引发,无论AppDomain
线程是什么开始.这意味着,这可以用作所有未处理异常的catch-all.
System.Windows.Application.Exit
:当WPF应用程序(即默认值AppDomain
)正常退出时引发.覆盖System.Windows.Application.OnExit
以利用它.
终结器(C#中的析构函数):当垃圾收集器释放非托管资源时运行.[总执行时间有限!].
活动顺序:
WPF应用程序:优雅退出
System.Windows.Application.Exit
System.AppDomain.CurrentDomain.ProcessExit
WPF应用程序:未处理的异常
System.AppDomain.CurrentDomain.UnhandledException
在TestDriven.NET中运行的MbUnit:通过测试(优雅退出)
System.AppDomain.CurrentDomain.DomainUnload
在TestDriven.NET中运行的MbUnit:测试失败(未处理的异常由MbUnit处理)
AppDomain.CurrentDomain.DomainUnload
问题: