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