在 PS 类 中引用程序集导致 "Unable to find type" 错误
Referencing assemblies inside PS classes causes "Unable to find type" error
我在 Windows 7 box 上使用 PowerShell 5.1,并试图从 PowerShell class 中引用 .NET 程序集中的类型,并得到一个 "Unable to find type"错误。
我的 "main" 程序是 FooProg。ps1,我正在其中创建 FooMod 的新实例 class
#Requires -Version 5.1
using module .\FooMod\FooMod.psm1
[FooMod]::new() | out-null
FooMod class 位于 FooMod 子文件夹的 PowerShell 模块 (FooMod.psm1) 中
#Requires -Version 5.1
using assembly .\Foo.dll
using namespace Foo
class FooMod {
FooMod() {
Write-Host "Start - Assembly access"
[Bar] $bar = [Bar]::new()
Write-Host $bar.Name
Write-Host $bar.Greeting()
Write-Host "Finish - Assembly access"
}
}
我的 Foo.dll 是根据以下 Bar.cs 构建的,与模块文件 (FooMod.psm1) 和模块清单文件 (FooMod.psd1) 一起位于 FooMod 子文件夹中
namespace Foo {
public class Bar {
public string Name;
public Bar(string name) => this.Name = name;
public Bar() : this("Bar") {
}
public string Greeting() {
return System.String.Format("Hello! My name is {0}", Name);
}
}
}
我在名为 FooMod.psd1 的 FooMod 子文件夹中还有一个模块清单,其中包含这些相关条目
RootModule = 'FooMod.psm1'
RequiredAssemblies = 'Foo.dll'
还有什么我想念的吗?在 class 之外使用程序集工作正常,实例化 PowerShell class(不引用程序集/外部类型)工作正常 - 但结合 PowerShell classes 和程序集类型是不行的!
想通了!事实证明,在主脚本 FooProg.ps1 中,using 语句需要引用 Module Manifest 并且 NOT Module Script.
所以不用
#Requires -Version 5.1
using module .\FooMod\FooMod.psm1
[FooMod]::new() | out-null
我改成了
#Requires -Version 5.1
using module .\FooMod\FooManifest.psd1
[FooModule]::new() | out-null
因此,我也将我的模块清单文件从 .\FooMod\FooMod.psd1 重命名为 .\FooMod\FooManifest.psd1
此外,在模块清单文件中,我将条目 RootModule = 'FooMod.psm1' 更改为 RootModule = 'FooModule.psm1'.这不是必需的更改,但有助于理解不同文件的结构。
这显然导致将模块脚本从 FooMod.psm1 重命名为 FooModule.psm1 并且还更改了 class 模块脚本中的名称从 FooMod 到 FooModule。同样不是必需的更改,但它与命名一致 classes 与包含它们的文件名相同。
整个练习让我相信在主脚本中命名的模块清单文件需要首先处理,以便在 RequiredAssemblies 中命名的程序集在在 RootModule 中命名的模块被解析。这使得外部 .NET 程序集中的类型在分析模块时可用,并防止出现 "Unable to find type" 错误。
现在配备了新的 FooModule.psm1 文件
#Requires -Version 5.1
using assembly .\Foo.dll
using namespace Foo
class FooModule {
FooModule() {
Write-Host "Start - Assembly access"
Write-Host
[Bar] $bar1 = [Bar]::new("Romeo")
Write-Host $bar1.Name
Write-Host $bar1.Greeting()
Write-Host
[Bar] $bar2 = [Bar]::new("Juliet")
Write-Host $bar2.Name
Write-Host $bar2.Greeting()
Write-Host
Write-Host "Finish - Assembly access"
}
}
我得到的输出如下
Start - Assembly access
Romeo
Hello! My name is Romeo
Juliet
Hello! My name is Juliet
Finish - Assembly access
关键是使用模块清单,正确设置 RequiredAssemblies 键并在主脚本中引用模块清单而不是模块脚本本身。
我在 Windows 7 box 上使用 PowerShell 5.1,并试图从 PowerShell class 中引用 .NET 程序集中的类型,并得到一个 "Unable to find type"错误。
我的 "main" 程序是 FooProg。ps1,我正在其中创建 FooMod 的新实例 class
#Requires -Version 5.1
using module .\FooMod\FooMod.psm1
[FooMod]::new() | out-null
FooMod class 位于 FooMod 子文件夹的 PowerShell 模块 (FooMod.psm1) 中
#Requires -Version 5.1
using assembly .\Foo.dll
using namespace Foo
class FooMod {
FooMod() {
Write-Host "Start - Assembly access"
[Bar] $bar = [Bar]::new()
Write-Host $bar.Name
Write-Host $bar.Greeting()
Write-Host "Finish - Assembly access"
}
}
我的 Foo.dll 是根据以下 Bar.cs 构建的,与模块文件 (FooMod.psm1) 和模块清单文件 (FooMod.psd1) 一起位于 FooMod 子文件夹中
namespace Foo {
public class Bar {
public string Name;
public Bar(string name) => this.Name = name;
public Bar() : this("Bar") {
}
public string Greeting() {
return System.String.Format("Hello! My name is {0}", Name);
}
}
}
我在名为 FooMod.psd1 的 FooMod 子文件夹中还有一个模块清单,其中包含这些相关条目
RootModule = 'FooMod.psm1'
RequiredAssemblies = 'Foo.dll'
还有什么我想念的吗?在 class 之外使用程序集工作正常,实例化 PowerShell class(不引用程序集/外部类型)工作正常 - 但结合 PowerShell classes 和程序集类型是不行的!
想通了!事实证明,在主脚本 FooProg.ps1 中,using 语句需要引用 Module Manifest 并且 NOT Module Script.
所以不用
#Requires -Version 5.1
using module .\FooMod\FooMod.psm1
[FooMod]::new() | out-null
我改成了
#Requires -Version 5.1
using module .\FooMod\FooManifest.psd1
[FooModule]::new() | out-null
因此,我也将我的模块清单文件从 .\FooMod\FooMod.psd1 重命名为 .\FooMod\FooManifest.psd1
此外,在模块清单文件中,我将条目 RootModule = 'FooMod.psm1' 更改为 RootModule = 'FooModule.psm1'.这不是必需的更改,但有助于理解不同文件的结构。
这显然导致将模块脚本从 FooMod.psm1 重命名为 FooModule.psm1 并且还更改了 class 模块脚本中的名称从 FooMod 到 FooModule。同样不是必需的更改,但它与命名一致 classes 与包含它们的文件名相同。
整个练习让我相信在主脚本中命名的模块清单文件需要首先处理,以便在 RequiredAssemblies 中命名的程序集在在 RootModule 中命名的模块被解析。这使得外部 .NET 程序集中的类型在分析模块时可用,并防止出现 "Unable to find type" 错误。
现在配备了新的 FooModule.psm1 文件
#Requires -Version 5.1
using assembly .\Foo.dll
using namespace Foo
class FooModule {
FooModule() {
Write-Host "Start - Assembly access"
Write-Host
[Bar] $bar1 = [Bar]::new("Romeo")
Write-Host $bar1.Name
Write-Host $bar1.Greeting()
Write-Host
[Bar] $bar2 = [Bar]::new("Juliet")
Write-Host $bar2.Name
Write-Host $bar2.Greeting()
Write-Host
Write-Host "Finish - Assembly access"
}
}
我得到的输出如下
Start - Assembly access
Romeo
Hello! My name is Romeo
Juliet
Hello! My name is Juliet
Finish - Assembly access
关键是使用模块清单,正确设置 RequiredAssemblies 键并在主脚本中引用模块清单而不是模块脚本本身。