如何在通过Add-Type定义的Powershell中使用接口?

问题描述 投票:1回答:3

我开发了一个PowerShell模块,它依赖于.NET程序集进行某些操作。 我重构了这个模块,不需要那个程序集,并注意到一些奇怪的行为,这阻止我最后删除该类:

Add-Type -TypeDefinition "public interface ICanTalk { string talk(); }" -Language CSharp

class Talker : ICanTalk {
    [string] talk() { return "Well hello there"; }
}

如果以交互方式运行此命令,则会成功。但是只要我在ISE或psm1文件中运行它“en-bloque”,它就会抛出一个错误,说它无法找到Add-Type调用中定义的接口。

我可以在Windows-PowerShell和PowerShell Core(6.0.2)中重现该问题

不同行为的原因是什么?我该如何解决?

powershell
3个回答
1
投票

补充your own answer

PowerShell classenum定义在执行开始之前进行解析,此类定义中引用的任何类型必须是:

  • 事先加载到当前会话中。
  • [自Windows PowerShell v5.1 / PowerShell Core 6.1.0起仅部分实现] 通过文件最顶部的using module / using assembly语句加载。 using module已经有效,但只有当引用的类型本身是class / enum定义时。 目前,尚未检测到从程序集加载的类型 - 无论是通过包含使用using moduleusing assembly导入的程序集的模块来直接加载程序集。 请参阅以下GitHub问题: #3461using module)和#2074using assembly#6652 - 跟踪所有与课程相关的问题的元问题。

同时,解决方法是通过使用模块清单的NestedModules条目,预先通过单独的脚本加载引用的类型。

  • 注意:ScriptsToProcess条目也可以工作,但它引用的脚本是dot-sourced(加载到调用者的当前范围内),而不是封闭模块。 使用来自已编译代码的类型(包括带有Add-Type的ad hoc编译代码),它也可以工作,因为这些类型总是可以在全局会话中使用,但是在概念上使用NestedModules更简洁,因为它在封闭模块的范围内点源脚本

1
投票

显然,PowerShell将在执行代码之前读取文件并处理类定义。

要解决这个问题,需要将Add-Type放入一个自己的脚本文件中,该文件在模块加载之前运行(或者在ISE中,只需在运行类定义之前运行代码)。

这可以通过使用PSD1文件中的ScriptsToProcess来完成。

感谢@TheIncorrigible1让我踏上了赛道。


0
投票

为什么不在单独的文件中定义C#中的所有类,而不是将其添加为Add-Type -path MyClasses.cs这样它将适用于较旧的PS版本

© www.soinside.com 2019 - 2024. All rights reserved.