我有一些PowerShell代码,我在调用一个.NET方法,它希望将一个类作为参数传递。
该方法接受一个空值作为参数,在C#中你可以按如下方式调用它:
var T = New Foo(null)
如果将其转换为PowerShell,可以尝试:
$T = New-Object Foo($null)
但是会返回以下错误
New-Object : Constructor not found. Cannot find an appropriate constructor for type Foo
Funilly,如果我将其称为:
,则会返回完全相同的错误$T = New-Object Foo
所以第一个问题是为什么? .NET是否认为$null
缺少某些内容,而不是来自.NET的类型null
?这就是为什么上面的两条指令返回相同的错误?
现在,我找到了解决此问题的方法如下:
$T = New-Object Foo(@($null))
这很好用,但是......为什么?
(@($Null)).GetType()
返回object[]
(@()).GetType()
也会返回object[]
,但如果我运行:
$T = New-Object Foo(@())
我仍然得到:
New-Object : Constructor not found. Cannot find an appropriate constructor for type Foo
那么,第二个问题:@(),@($ null)和$ null之间有什么区别?
此外,还有最后一个问题,这是我不明白的其他问题。
假设我有另一个.NET方法Bar(string, Foo)
如果我打电话:
$B = New-Object Bar("s", $null)
这很好用,无需将其转换为对象[]或类似的东西。
所以第三个也是最后一个问题是:为什么参数的数量会影响它是否需要作为数组传递?
我的猜测是,如果我将它转换为数组,我会称之为
$B = New-Object Bar(@("s", $null))
这意味着即使该方法需要两个参数,我只将其作为一个对象数组传递给它,然后它会自动将每个数组项映射到参数上,但这仍然不能为前两个问题:)
修改
我知道@()是一个空数组,@($ null)是一个数组,其中一个元素恰好是null,所以这不是我要问的。
但是,如果打电话:
$T = New-Object Foo($null)
让Foo的构造函数看不到传递的参数,为什么调用@()
vs调用@($null)
会有所不同?在这种情况下,@($null)
当然应该与@()
相同,因为在.NET方法中看不到参数。
为什么$null
有时意味着什么,有时甚至什么都没有?
答案 0 :(得分:6)
根据您的编辑,您可以很好地理解$ null和@($ null)之间的差异。
与正常调用.Net方法不同,调用构造函数需要先调用New-Object cmdlet。 New-Object的语法是:
New-Object [-TypeName] <string> [[-ArgumentList] <Object[]>] [-Property <IDictionary>]
让我们想一想New-Object的工作原理。使用反射,New-Object将调用TypeName.GetConstructors()并找到可以接受n个参数的候选构造函数,其中n是ArgumentList中的参数个数。
如果你像这样调用New-Object:
New-Object -TypeName Foo
然后ArgumentList的值为$ null。你没有传递$ null,但无论如何这都是它的价值。如果ArgumentList是$ null,则没有参数。在这个例子中,很明显,你没有指定-ArgumentList。如果你写:
New-Object -TypeName Foo -ArgumentList $null
这最终会得到相同的最终结果 - 没有参数列表。 ArgumentList需要[object []],$ null是[object []]的完全有效值,但这意味着没有参数。
如果你写:
New-Object -TypeName Foo -ArgumentList @($null)
现在你传递的是一个[object []],它有一个值,值为$ null,一切都按预期工作。
这无疑令人困惑,但它有助于思考如何实现自己调用另一个函数并接受param数组的C#函数。如果您的param数组为null,则不会收到额外的参数。
在某些情况下,New-Object可能会更加混乱。我个人被重载的构造函数绊倒,一个采用数组,另一个采用多个参数。在C#中,构造函数类似于:
Foo(object[] array); // #1
Foo(string s, int i); // #2
我错误地尝试调用构造函数#1:
New-Object -TypeName Foo -ArgumentList @($array)
这会调用构造函数#2,因为New-Object总是希望[object []]传递多个参数,而你很少想要使用单个数组参数调用构造函数。正确的PowerShell将是:
New-Object -TypeName Foo -ArgumentList (,$array)
由于这种混淆,我在PowerShell V5中添加了一种调用构造函数的新方法。它现在可以作为一个非常早期的预览版(http://www.microsoft.com/en-us/download/details.aspx?id=42936),语法看起来像一个静态方法调用:
[Foo]::new($name, $count)
使用这种新语法,调用构造函数不再令人困惑,并且作为附带好处,它也比调用New-Object快一个数量级。
编辑:我使用重载的构造函数更正了示例。