@($ null)和$ null之间的差异

时间:2014-08-18 09:35:34

标签: .net powershell

我有一些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有时意味着什么,有时甚至什么都没有?

1 个答案:

答案 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快一个数量级。

编辑:我使用重载的构造函数更正了示例。