函数中的参数类型验证 - 二进制模块与脚本模块

Jan*_*oek 7 c# powershell type-conversion

构建了许多PowerShell模块(包括二进制和脚本)之后,两个模型之间仍然存在一些不一致的问题,我无法理解这些模块.也许你们中的一个人可以对这个问题有所了解.

  1. 想象一个接受单个DateTime值的函数.在脚本函数中,我将其定义为[DateTime]参数; 在C#函数中,参数将是类型DateTime.到现在为止还挺好.

  2. 现在想象一下将DateTime函数传递给函数,其中添加了一个额外的note属性Add-Member.尽管被定义为a [DateTime],脚本函数参数很乐意接受这个值,因为它实际上是PSObject包装原始DateTime(并且可能包含其他成员)在使用时被解包 - 我希望我在这里使用正确的术语.正如预期的那样,传递除(包装)之外的其他东西DateTime会失败,从而使该功能或多或少类型安全.

  3. 等效的C#函数将参数定义为a DateTime,因此AFAIK无法访问其他参数.毕竟,参数提供的唯一"接口"来自DateTime类型.

  4. 或者,我可以定义的C#函数的参数类型的PSObject,但我会做我自己的类型检查了PSObjectBaseObject.

我的逻辑中有缺陷吗?或者,更重要的是,有没有办法绕过这个,所以我仍然可以将我的二进制模块的类型检查留给PowerShell?

提前谢谢了!

Mat*_*sen 4

你既对又错——这完全取决于目标参数是否是值类型(System.DateTime例如是一个结构)——在这种情况下,在参数绑定期间,类型强制会丢失所有内容。

但是,如果参数类型是引用类型,您可以使用“复活”PSObject 包装器PSObject.AsPSObject()

为了便于复制,我在纯 PowerShell 中提出了以下示例,但我相信它充分说明了我的观点

将以下内容粘贴到 C# 源文件中(例如TestCmdlets.cs):

using System;
using System.Management.Automation;

namespace TestPSObject
{
  // This will be our parameter type
  public class TestObject {}

  // This will be our reference type test cmdlet
  [Cmdlet(VerbsDiagnostic.Test, "PSObjectByRef")]
  public class TestPSObjectByRefCommand : Cmdlet
  {
    [Parameter(Mandatory=true)]
    public TestObject TestObject
    {
      get { return testObject; }
      set { testObject = value; }
    }
    private TestObject testObject;

    protected override void ProcessRecord()
    {
      // If this works, we should receive an object with
      // identical psextended properties
      WriteObject(PSObject.AsPSObject(this.TestObject));
    }
  }

  // This will be our value type test cmdlet
  [Cmdlet(VerbsDiagnostic.Test, "PSObjectByValue")]
  public class TestPSObjectByValueCommand : Cmdlet
  {
    [Parameter(Mandatory=true)]
    public DateTime DateTime
    {
      get { return dateTime; }
      set { dateTime = value; }
    }
    private DateTime dateTime;

    protected override void ProcessRecord()
    {
      // If this works, we should receive an object with
      // identical psextended properties (hint: we won't)
      WriteObject(PSObject.AsPSObject(this.DateTime));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,在您的 shell 中,编译并导入我们的测试模块:

Add-Type -Path .\TestCmdlets.cs -OutputAssembly TestPSObject.dll -OutputType Library
Import-Module .\TestPSObject.dll
Run Code Online (Sandbox Code Playgroud)

接下来我们创建测试主题并为其添加注释属性:

$TestObject = New-Object TestPSObject.TestObject
$TestObject |Add-Member -MemberType NoteProperty -Name TestProperty -Value "Hi there!"
$DateTime = Get-Date
$DateTime |Add-Member -MemberType NoteProperty -Name TestProperty -Value "Hi there!"
Run Code Online (Sandbox Code Playgroud)

Hi there!现在,当您取消引用该成员时,它们都返回字符串值TestProperty

现在进行实际测试:

$TestObjectAfter = Test-PSObjectByRef -TestObject $TestObject
$DateTimeAfter   = Test-PSObjectByValue -DateTime $DateTime
Run Code Online (Sandbox Code Playgroud)

这仍然会返回Hi there!

$TestObjectAfter.TestProperty
Run Code Online (Sandbox Code Playgroud)

但这不会:

$DateTimeAfter.TestProperty
Run Code Online (Sandbox Code Playgroud)