9

I'm trying to use PowerShell's classes that is very handy way of grouping related data together and facing quite tedious to deal with behavior. The simplified scenario: one PS script that defines class and another script that uses that class.

Common.ps1

class X
{
    [string] $A
} 

Script1.ps1

. $PSScriptRoot\Common.ps1

[X] $v = New-Object X

Everything is good - you can run Script1.ps1 arbitrary amount of times with no issues - until you make any change in Common.ps1. You will face the following error.

Cannot convert the "X" value of type "X" to type "X".
At D:\temp\PSIssue\Script1.ps1:3 char:1
+ [X] $v = New-Object X
+ ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException

Conceivably any change (even if you just added whitespace) in PS file forces its recompilation, so that type X becomes different than X it used to be - temporary container assembly has been changed (the very same issue easily reproducible in .NET - types are identical as long as "Fully Qualified Assembly Names" are the same). Change in Script1.ps1 makes things function normally again.

Is there any way to overcome such kind of issues?

Eugene D. Gubenkov
  • 5,127
  • 6
  • 39
  • 71
  • 3
    Yes, don't use two different implementations of `X` in the same runspace/session/appdomain (ie. `exit` powershell, re-launch) – Mathias R. Jessen Apr 23 '16 at 00:01
  • @MathiasR.Jessen, is there any way in PowerShell ISE to reload/recompile everything? I'm currently closing it completely and open from scratch ... – Eugene D. Gubenkov Apr 23 '16 at 08:24
  • If you are wiling to ignore the error and just run the script a second time I do not get the error and run again then I get the updated class. Should be fine for fine testing. – Matt Apr 23 '16 at 16:31
  • @Matt, hm, I'm not observing what you're saying - it keeps showing the same error for me. You can check it out: http://screencast.com/t/1w8x73D4. – Eugene D. Gubenkov Apr 23 '16 at 18:15

1 Answers1

5

I was able to replicate and resolve your issue. It is similar to if you define a class in a scope and you try to define another class in the same scope. The class definition is retained in PowerShell session. In Script1.ps1 you need to modify the code to not explicitly declare the variable to type. Just use as below to not use Strong Typing and let PowerShell determine the type and assign it dynamically:

. $PSScriptRoot\Common.ps1

$v = New-Object X

Now you should be able to change the definition of class X in Common.ps1 as many times as you want without needing to close and reload.

The example above uses "Weak typing" You can read more about this and other details here: Variable Types and Strongly Typing

Burkart
  • 462
  • 4
  • 9
Aman Sharma
  • 1,930
  • 1
  • 17
  • 31
  • 1
    If this is true than mean you could also just `Remove-Variable v` as well – Matt Apr 23 '16 at 15:31
  • That wont work with Strongly typed variable as PowerShell still binds the variable to it's older definition. I tried it to be sure and observed same result as original question. To resolve you need to use Weakly typed variable as I showed in the example. – Aman Sharma Apr 23 '16 at 16:03
  • @AmanSharma, thank you for the suggestion, it definitely works, but I find explicit types very handy in scripts development - it either more clear and allows IDE to do better job in auto-completion... – Eugene D. Gubenkov Apr 23 '16 at 18:06
  • I agree @EugeneD.Gubenkov that explicit types are good practice. But the auto-completion will still work with weakly typed variables. You will just have to execute once and let ISE know the type info. Please accept as answer if this resolves your problem. – Aman Sharma Apr 23 '16 at 18:15
  • @AmanSharma, I believe it works in this particular and similar simplest cases. – Eugene D. Gubenkov Apr 23 '16 at 18:17
  • @AmanSharma, wow! ISE is way smarter than I thought! http://i.stack.imgur.com/A4FFn.png - after first run of scripts it remembers the type and gives you powerful and smart auto-completion – Eugene D. Gubenkov Apr 23 '16 at 18:32
  • @EugeneD.Gubenkov I am glad it helped! – Aman Sharma Apr 23 '16 at 18:36
  • @AmanSharma Nicely spotted but Matt is also right (just tested myself). PowerShell doesn't actually have strong typing, so it emulates type constraints by assigning an attribute to the variable itself (inspect `(Get-Variable v).Attributes` for yourself to see this) - this is cleared when the variable is removed from the scope with `Remove-Variable` – Mathias R. Jessen Apr 24 '16 at 20:54
  • @MathiasR.Jessen, I've just checked Remove-Variable - it results with the same error for me: http://screencast.com/t/CIEZISMe... – Eugene D. Gubenkov Apr 26 '16 at 20:35