PowerShellPracticeAndStyle icon indicating copy to clipboard operation
PowerShellPracticeAndStyle copied to clipboard

Avoid New-Object

Open Jaykul opened this issue 9 years ago • 4 comments

In modern PowerShell, you should almost always avoid New-Object, because it is much slower than other methods of creating objects, like using the constructor directly via ::new( or casting a hash-table. Both the [PSObject]::new() constructor and casting are supported in all actively supported versions of PowerShell.

As always, there are some exceptions to this rule, such as when you need to create a type from a string input, or need to create a ComObject, and you may sometimes get more readable code, such as when you need to pass arguments to the constructor as well as property values.

It's also worth pointing out there is at least one special case: hash tables. PowerShell's normal hash tables, created with literal @{ key = "value" } syntax, are case insensitive, but hash tables created via constructor syntax [hashtable]::new() or New-Object Hashtable use the .NET default case sensitive hash tables.

Jaykul avatar Jun 23 '16 22:06 Jaykul

I think that the use New-Object should be general avoided as it is legacy (change issue title?) and even counts for any object creation including something like: New-Object System.Drawing.Size(800, 600) --> [System.Drawing.Size]::new(800, 600)

iRon7 avatar Dec 06 '24 15:12 iRon7

What I mean above is that New-Object should not be used to create hash tables -- because it produces unexpected and incorrect results. That is, you should almost always use the literal @{ ... } hash table, not because New-Object is slower, and totally unnecessary, but because the cmdlet makes the hash table case sensitive which is unexpected, and usually wrong, in PowerShell. Of course, if you need a case sensitive hash table, then you have to use the [hashtable]::new() or New-Object hashtable.

What the article points out is that New-Object is quite a bit slower to create PSObject than using the new casting syntax with [PSCustomObject]@{ ... } -- however, it is backward compatible to older versions of PowerShell. It literally always works, even in old versions where the new syntax does not.

We could also make this case generically for any type that has a default/empty constructor, since you can then cast a hashtable to them.

And of course (as you wrote in the linked issue), we could make that case for calling the constructor using the ::new syntax -- although that's a totally different situation than the PSCustomObject syntax (calling parameterized constructors, vs the default constructor and setting properties), and is even newer.

In the general case, you should avoid New-Object when you can use either of the new syntaxes. However, although it's slower to use New-Object than the ::new(...) operator or the cast operator, the cmdlet works on older versions, and if you need to both pass constructor arguments and set a bunch of property values, it can still be a lot more readable (albeit probably still slower).

Jaykul avatar Dec 16 '24 05:12 Jaykul

What I mean above is that New-Object should not be used to create hash tables...

I understand your point and completely agree with the ins and outs related to this issue (and the one I mentioned). By the way, I reported a PowerShell issue once that shows the implied disadvance of using the literal initializer: #23986 PSCustomObject unnoticeably merges similar keys 😀.

Anyways, what I mean was that the PowerShell Practice And Style Guide might include some (more general) guidance about the use of the New-Object cmdlet vs literal initializer (whatever the direction might be).

I understand also that this differs from your initial request, so let me know if you think it might make more sense to open a new issue for this instead.

iRon7 avatar Dec 16 '24 16:12 iRon7

You are right that it would be worthwhile making the general recommendation as well. I have changed the original post to reflect what I would propose...

Jaykul avatar Dec 17 '24 04:12 Jaykul