提问人:Ralf_Reddings 提问时间:9/6/2023 最后编辑:mklement0Ralf_Reddings 更新时间:9/6/2023 访问量:194
PowerShell 类:是否可以将构造函数参数设置为可选?
PowerShell Classes: Is it possible to make a constructors parameter optional?
问:
我正在尝试为电影/动画中使用的时间码约定构建一个“类型”。
我想适应用户可能希望使用从其他地方获取的时间码字符串初始化对象的用例:
$MyTimeCode = [TimeCode]::new("08:06:04.10", 12)
在其他情况下,直接使用属于类构造函数的参数:
$MyTimeCode = [TimeCode]::new(, 8, 6, 4, 10, 12)
#If I had constructor such as the foloowing in my class definition:
#TimeCode([String]$TimeStamp, [Int]$Hours, [Int]$Minutes, [Int]$Seconds, [Int]$Frames, [Int]$FrameRate)
`
以下类为例:
class HelloWorld {
[String]$Hello
[String]$World
HelloWorld([String]$Hello, [String]$World) {
$This.Hello = $Hello
$This.World = $World
}
}
尝试初始化它工作正常,但我收到错误:[HelloWorld]::new("Hello", "World")
[HelloWorld]::new("Hello")
MethodException: Cannot find an overload for "new" and the argument count: "1".
我一直在看一些讲座,但它们根本没有结构,而且进展很快。
官方文档通常是我的首选,但“About_Classes”页面通过“机架”和“设备”示例迅速发展到“继承”和“子类”等,我不清楚如何开始只使用一个类。
我的目标是熟悉课程以及它们可以做什么。时间码是次要的。
答:
需要一个接受单个参数的构造函数。只要每个参数的签名是唯一的,就可以根据需要有任意数量的构造函数。此代码还会创建默认构造函数。默认构造函数的成员在实例化时将包含。$null
class HelloWorld {
[String]$Hello
[String]$World
HelloWorld([String]$Hello, [String]$World) {
$This.Hello = $Hello
$This.World = $World
}
HelloWorld([String]$Hello) {
$This.Hello = $Hello
$This.World = 'default'
}
HelloWorld() {} # default constructor
}
$x1 = [HelloWorld]::new('hello', 'world')
$x1
$x2 = [HelloWorld]::new('hello')
$x2
$x3 = [HelloWorld]::new()
$x3
评论
要向 lit 的有效解决方案添加一些背景信息,请执行以下操作:
你要查找的功能需要以下功能之一,这些功能在 PowerShell 中不可用,在 Windows PowerShell(不再处于活动开发状态)中不可用,在积极开发的 PowerShell (Core)(截至 v7.3.x,截至撰写本文时的稳定版本)中不可用:
可选的方法/构造函数参数,最好与命名参数结合使用。
不支持可选参数,即使 PowerShell 允许定义它们:
# !! Does NOT work as of PowerShell 7.3.x # !! The default value is QUIETLY ACCEPTED, but IGNORED. class Foo { [void] Bar($baz, $quux = 42) {} } # !! FAILS, because you must supply arguments for BOTH parameters. # !! -> 'Cannot find an overload for "Bar" and the argument count: "1"' [Foo]::new().Bar('hi')
- GitHub 问题 #9701 是一个功能请求,要求实现可选参数。
从根本上不支持命名参数。
- GitHub 问题 #13307 是一个旨在改变这一点的功能请求。
构造函数链接,即具有多个构造函数重载,这些重载可以使用默认值相互调用,PowerShell 从 v7.3.x 开始不支持:
class Foo { # Two-parameter constructor Foo($bar, $baz) { <# ... #> } # Single-parameter constructor Foo($bar) { # !! Constructor chaining Does NOT work as of PowerShell 7.3.x: # !! That is, the attempt to call the two-parameter constructor # !! (with a default value for the second parameter) causes a SYNTAX ERROR. $this($bar, 'default for $baz') } }
有关通过隐藏帮助程序方法的解决方法,请参阅此答案。
- 在简单情况下,如果代码重复不是问题,您可以 只需创建单独的、独立的构造函数重载,如 LIT 的回答所示。
GitHub 问题 #19969 是一个功能请求,要求实现构造函数链接(以及其他功能)。
这是 C# 类允许您执行的操作,即:
public class HelloWorld
{
public string? Hello { get; set; }
public string? World { get; set; }
public HelloWorld(string? hello = null, string? world = null)
{
Hello = hello;
World = world;
}
}
将允许在单个构造函数中实例化的 3 种可能性(无参数、1 个参数或 2 个参数)。PowerShell 类远非如此......相当令人失望。从好的方面来说,Add-Type
可用于内联 C#。
添加到其他答案的其他替代方案:
- 无构造函数类和哈希表来实例化您的对象,缺点是您必须在此处使用命名参数......
class HelloWorld {
[string] $Hello
[string] $World
}
[HelloWorld]@{ Hello = 'foo' }
[HelloWorld]@{ World = 'bar' }
- 用户定义的显式和隐式转换运算符,一个简单的例子:
class HelloWorld {
[string] $Hello
[string] $World
HelloWorld([string] $Hello, [string] $World) {
$this.Hello = $Hello
$this.World = $World
}
# targets a `$hello` only explicit casting
static hidden [HelloWorld] op_Explicit([string] $Hello) {
return [HelloWorld]::new($Hello, 'myDefaultValue')
}
}
[HelloWorld] 'foo'
按照开头的 C# 示例,Mathias 的有用回答中也显示了这一点。
注意:编译需要 PowerShell 7+,这将在 Windows PowerShell 5.1 中失败。
Add-Type '
public class HelloWorld
{
public string? Hello { get; set; }
public string? World { get; set; }
public HelloWorld() : this("hey", "there")
{ }
public HelloWorld(string? hello = "hey", string? world = "there")
{
Hello = hello;
World = world;
}
}' -IgnoreWarnings -WarningAction Ignore
[HelloWorld]::new()
# Hello World
# ----- -----
# hey there
[HelloWorld]::new('hi')
# Hello World
# ----- -----
# hi there
[HelloWorld]@{ world = 'you' }
# Hello World
# ----- -----
# hey you
评论