Difference between @ ($ null) and $ null

I have PowerShell code where I am calling a .NET method that expects a class to be passed as a parameter.

The method takes a null value as a parameter, and in C # you call it like this:

var T = New Foo(null)

      

If you translate this into PowerShell try:

$T = New-Object Foo($null)

      

But this returns the following error

New-Object : Constructor not found. Cannot find an appropriate constructor for type Foo

      

Probably the same error is returned if I call it like:

$T = New-Object Foo

      

So why does the first question? .NET see it $null

as the absence of something, as against the type null

from .NET? So the above two instructions return the same error?

Now I have found a way to solve this problem like this:

$T = New-Object Foo(@($null))

      

This works great, but ... why?

(@($Null)).GetType()

returns object[]

(@()).GetType()

also returns object[]

, but if I run:

$T = New-Object Foo(@())

      

I am still getting:

New-Object : Constructor not found. Cannot find an appropriate constructor for type Foo

      

So the second question is, what is the difference between @ (), @ ($ null) and $ null?

Also, and the last question is something that I don't understand yet.

Let's say I have another .NET method: Bar(string, Foo)

If I call:

$B = New-Object Bar("s", $null)

      

This works great without having to convert it to an [] object or anything like that.

So, the third and last question: why does the number of parameters affect whether you need to pass it as an array or not?

I guess if I had to pass it to an array I would call it

$B = New-Object Bar(@("s", $null))

      

Considering that even if the method expects two parameters, I only pass it one as an array of objects, and then it automatically maps each element of the array to the parameters, but that still doesn't answer the first two questions :)

EDIT

I know that @ () is an empty array and that @ ($ null) is a single element array which turns out to be null, so not what I'm asking.

However, if the call:

$T = New-Object Foo($null)

Creates a constructor Foo without specifying a passed parameter, why is @()

vs call @($null)

different? Of course, @($null)

should be the same as @()

, in this case the absence of a parameter, as seen in the .NET method.

Why $null

does it sometimes mean something and sometimes nothing at all?

+3


source to share


1 answer


Based on your editing, you are well aware of the differences between $ null and @ ($ null).

Unlike a regular .Net method call, calling the constructor requires you to call the New-Object cmdlet first. Syntax for New-Object:

New-Object [-TypeName] <string> [[-ArgumentList] <Object[]>] [-Property <IDictionary>]

      

Think about how New-Object works. Using reflection, New-Object will call TypeName.GetConstructors () and find candidate constructors that can take n arguments, where n is the number of arguments in the ArgumentList.

If you call New-Object like this:

New-Object -TypeName Foo

      

Then ArgumentList is $ null. You didn't pass in $ null, but it's still the value. If ArgumentList is $ null, there are no arguments. It's obvious in this example, you didn't specify -ArgumentList. If you write:

New-Object -TypeName Foo -ArgumentList $null

      

The result is the same end result - there is no argument list. The List argument expects [object []], and $ null is a perfectly valid value for [object []], but that means there are no arguments.

If you write:

New-Object -TypeName Foo -ArgumentList @($null)

      

Now you pass [object []] with a single value, $ null, and everything works as you expect.



This is undoubtedly confusing, but it helps to think about how you can implement your own C # function that calls another function and takes a param array. If your param array is null, you haven't received any additional arguments.

The new object can be even more confusing in some cases. I personally worked with overloaded constructors, one took an array and the other took multiple arguments. In C #, the constructors were something like this:

Foo(object[] array);   // #1
Foo(string s, int i);  // #2

      

And my flawed attempt to call constructor # 1:

New-Object -TypeName Foo -ArgumentList @($array)

      

This calls constructor # 2 because New-Object always expects [object []] to pass multiple arguments and rarely do you want to call a constructor with a single array argument. Correct PowerShell would be:

New-Object -TypeName Foo -ArgumentList (,$array)

      

Because of this confusion, I added a new way to call constructors in PowerShell V5. It's available as a very early preview now ( http://www.microsoft.com/en-us/download/details.aspx?id=42936 ), the syntax looks like a static method call:

[Foo]::new($name, $count)

      

With this new syntax, calling constructors are no longer confusing, and as a side benefit, it's also an order of magnitude faster than calling New-Object.

EDIT: I fixed the example with overloaded constructors.

+6


source







All Articles