最初,我认为只有在调用此类上标记的cmdlet时,PowerShell才会实例化一个类。执行时,每个cmdlet都属于BeginProcess - > ProcessRecord - > EndProcess(StopProcess)路径,在EndProcess完成之后,似乎进程将结束,然后内存将所有这些类对象收集为垃圾。因此每个类应该存在于自己的生命周期中而不共享任何资源。当我们调用这些cmdlet时,
但是我发现类在同一个模块中共享相同的静态值。例如,假设在我的项目中我有两个类:
namespace PSDSL
{
[Cmdlet(VerbsCommon.Get, "MyTest")]
public class GetMyTest : Cmdlet
{
public static GlobalUserName = "";
[Parameter(Mandatory = false)]
public string Filepath { get; set; }
protected override void InnerProcessRecord()
{
if (_filepath != null)
{
GlobalUserName = _filepath;
}
Console.WriteLine(GlobalUserName);
}
}
}
namespace PSDSL
{
[Cmdlet(VerbsCommon.Get, "MyTest2")]
public class GetMyTest2 : Cmdlet
{
[Parameter(Mandatory = false)]
public string Filepath { get; set; }
protected override void InnerProcessRecord()
{
if (_filepath != null)
{
GlobalUserName = _filepath;
}
Console.WriteLine(GlobalUserName);
}
}
}
除了定义静态GlobalUserName之外,这两个命令非常相似。调用这两个cmdlet表示可以从两个cmdlet读取/写入GlobalUserName。
我的困惑在于,什么时候课程会被实现?
答案 0 :(得分:2)
立即加载整个程序集并保持加载状态,直到重新启动PowerShell提示符。
<强>详细信息:强>
.Net中最小的代码隔离单元是Assembly(在大多数情况下是单个托管DLL)。
使用托管运行时的进程一次加载的次数少于单个程序集 - 因此该程序集中的所有类(以及相关的一次性请求)将一起加载。因此,所有静态字段将同时出现在内存中(请注意,静态字段在首次使用类之前初始化“,这意味着它们不必在程序集加载时初始化)。
如果不使用单独的AppDomain,也无法“卸载”类甚至程序集。 PowerShell不使用多个AppDomain来加载不同模块的程序集(通常在实现过程中需要特别注意交叉AddDomain调用,现在你已经了解它)。结果一旦加载模块保留在内存中,直到您退出PowerShell(Powershell Unload Module... completely中所述)。
由于程序集为其中的所有命令行开关加载一次,所有静态字段将立即出现并保持值直到退出PowerShell。
附注:我强烈建议避免使用static
字段,除了一般的静态不可变数据。这是容易在那里留下一些随机值并影响未来代码的方法。在PowerShell管道中是在命令行开关之间传递信息的方式,其他类型的进程(WinForms,ASP.Net,...)有他们自己的首选机制来传递数据而不是使用静态。