【问题标题】:Parameter type validation in functions - binary modules vs. script modules函数中的参数类型验证 - 二进制模块与脚本模块
【发布时间】:2018-07-02 08:45:15
【问题描述】:

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

  1. 想象一个接受单个DateTime 值的函数。在脚本函数中,我将其定义为[DateTime] 参数;在 C# 函数中,参数的类型为 DateTime。到目前为止,一切顺利。

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

  3. 等效的 C# 函数将参数定义为 DateTime,因此 AFAIK 无法访问附加参数。毕竟参数提供的唯一“接口”来自DateTime类型。

  4. 或者,我可以将 C# 函数的参数类型定义为 PSObject,但是我必须自己检查 PSObjectBaseObject

我的逻辑有问题吗?或者,更重要的是,有没有办法解决这个问题,以便我仍然可以将二进制模块的类型检查留给 PowerShell?

非常感谢!

【问题讨论】:

    标签: c# powershell type-conversion


    【解决方案1】:

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

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

    为了便于复制,我在纯 (-ish) 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));
        }
      }
    }
    

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

    Add-Type -Path .\TestCmdlets.cs -OutputAssembly TestPSObject.dll -OutputType Library
    Import-Module .\TestPSObject.dll
    

    接下来我们创建我们的测试主题并为它们添加一个 note 属性:

    $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!"
    

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

    现在进行实际测试:

    $TestObjectAfter = Test-PSObjectByRef -TestObject $TestObject
    $DateTimeAfter   = Test-PSObjectByValue -DateTime $DateTime
    

    这仍然会返回Hi there!:

    $TestObjectAfter.TestProperty
    

    但这不会:

    $DateTimeAfter.TestProperty
    

    【讨论】:

    • 非常感谢您的详尽回答!现在完全清楚了。不得不问这个我觉得有点傻,但我很高兴我做到了! :-)
    • @JanHoek 乐于助人!不是没有愚蠢的问题;-)
    猜你喜欢
    • 2014-01-07
    • 2023-03-17
    • 2022-12-04
    • 2020-12-27
    • 1970-01-01
    • 1970-01-01
    • 2014-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多