是否可以覆盖PowerShell 5类中的Getter/Setter函数?

OCr*_*m85 9 powershell

我最近开始用powershell 5创建类.当我关注这个很棒的指南时https://xainey.github.io/2016/powershell-classes-and-concepts/#methods

我想知道是否有可能覆盖get_xset_x方法.

例:

Class Foobar2 {
    [string]$Prop1    
}

$foo = [Foobar2]::new()
$foo | gm



Name        MemberType Definition                    
----        ---------- ----------                    
Equals      Method     bool Equals(System.Object obj)
GetHashCode Method     int GetHashCode()             
GetType     Method     type GetType()                
ToString    Method     string ToString()             
Prop1       Property   string Prop1 {get;set;}  
Run Code Online (Sandbox Code Playgroud)

我想这样做是因为我认为除了使用我的自定义GetSet方法之外,其他人访问属性会更容易:

Class Foobar {
    hidden [string]$Prop1

    [string] GetProp1() {
        return $this.Prop1
    }

    [void] SetProp1([String]$Prop1) {
        $this.Prop1 = $Prop1
    }
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*sen 13

不幸的是,新的Classes功能没有getter/setter属性的功能,就像你从C#中了解它们一样.

但是,您可以将ScriptProperty成员添加到现有实例,该实例将表现出与C#中的属性类似的行为:

Class FooBar
{
    hidden [string]$_prop1
}

$FooBarInstance = [FooBar]::new()
$FooBarInstance |Add-Member -Name Prop1 -MemberType ScriptProperty -Value {
    # This is the getter
    return $this._prop1
} -SecondValue {
    param($value)
    # This is the setter
    $this._prop1 = $value
}
Run Code Online (Sandbox Code Playgroud)

现在您可以$_prop1通过Prop1对象上的属性访问:

$FooBarInstance.Prop1
$FooBarInstance.Prop1 = "New Prop1 value"
Run Code Online (Sandbox Code Playgroud)


小智 8

实际上,我可能会建议另一种方法来解决 PowerShell 类的限制,因为以这种方式添加脚本属性的成本很高(使用实例的构造函数和 Add-Member 命令),因为这意味着每次创建此类的实例:-(

想象一下创建数百个(或者可能是数千个此类)对象的场景,例如:

$myList = 1..10|% { $obj = [FooBar]::new();  $obj.Prop1 = "$_"; $obj; }
Run Code Online (Sandbox Code Playgroud)

上面的代码将创建该类的 10 个对象并保存在变量中。

通过使用 (Write-Host) 将显示消息添加到大蟒蛇的答案中,如下所示:

Class myFooBar
{
    hidden [string]$_prop1

    myFooBar(){
        #Display message for this solution.
        Write-Host "Prop1 Setup (Called Many Times)" -ForegroundColor  Cyan;
        $this | Add-Member -Name Prop1 -MemberType ScriptProperty -Value {
            # This is the getter
            return $this._prop1
        } -SecondValue {
            param($value)
            # This is the setter
            $this._prop1 = $value
        }
    }


}
Run Code Online (Sandbox Code Playgroud)

现在尝试与上面创建 10 个对象相同的测试:

$myList = 1..10|% { $obj = [myFooBar]::new();  $obj.Prop1 = "$_"; $obj; }
Run Code Online (Sandbox Code Playgroud)

这将生成以下输出:

Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Run Code Online (Sandbox Code Playgroud)

如果您的类具有大量属性并且您计划在运行时创建该类的数百个实例,则这种行为会更糟。

更好的解决方案:

可以通过利用(静态构造函数)和(Update-TypeData)来实现,即使您再次运行测试,也只会创建一次属性,不会将更多属性添加到所有实例,因为它们已添加到类型数据一次(这将直接影响所有新实例)。

为了更清楚起见,我将修改类代码并添加另一个名为 prop2 的属性,但使用 myFooBar 类型的静态修改而不是实例创建者(并使用Update-TypeData命令而不是Add-Member),如下所示:

Class myFooBar
{
    hidden [string]$_prop1
    hidden [string]$_prop2

    myFooBar(){
        Write-Host "Prop1 Setup (Called Many Times)" -ForegroundColor  Cyan;
        $this | Add-Member -Name Prop1 -MemberType ScriptProperty -Value {
            # This is the getter
            return $this._prop1
        } -SecondValue {
            param($value)
            # This is the setter
            $this._prop1 = $value
        }
    }

    static  myFooBar(){
        Write-Host "Prop2 Setup (Only Once)" -ForegroundColor  Yellow;
        "myFooBar" | Update-TypeData -MemberName Prop2 -MemberType ScriptProperty -Value {
            # This is the getter
            return $this._prop2;
        } -SecondValue {
            param($value)
            # This is the setter
            $this._prop2 = $value;
        } -Force
    }
}
Run Code Online (Sandbox Code Playgroud)

运行我们的创建测试两次,如下所示:

write-host "Test (first call):-----------------" -ForegroundColor Green;
$myList1 = 1..10|% { $obj = [myFooBar]::new();  $obj.Prop1 = "$_"; $obj.Prop2 = "$_"; $obj; };

write-host "Test (Second call):-----------------" -ForegroundColor Green;
$myList2 = 1..10|% { $obj = [myFooBar]::new();  $obj.Prop1 = "$_"; $obj.Prop2 = "$_"; $obj; };
Run Code Online (Sandbox Code Playgroud)

输出如下:

Test (first call):-----------------
Prop2 Setup (Only Once) # <------------------ (Prop2)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Test (Second call):-----------------
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Prop1 Setup (Called Many Times)
Run Code Online (Sandbox Code Playgroud)

请注意,Prop2 设置代码执行一次,无论您创建多少个对象或重复调用多少次,都不会创建更多属性,因为它们已添加到本身的类型而不是实例中。

谢谢。


Rob*_*ere 5

只是为了扩大Mathias的答案...

您可以将“ add-member”部分包括到该类的构造函数中,以便只需实例化该类即可自动添加该部分。

以Mathias的答案为例:

Class FooBar
{
    hidden [string]$_prop1

    FooBar(){
        $this | Add-Member -Name Prop1 -MemberType ScriptProperty -Value {
            # This is the getter
            return $this._prop1
        } -SecondValue {
            param($value)
            # This is the setter
            If ($value -eq 'foo'){$value = 'bar'}
            $this._prop1 = $value
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

创建与该类同名的类方法将覆盖该类的“构造函数”。每当您创建新的“ foobar”对象时,该方法中的代码部分都将运行。在这里,我们合并了Add-Member cmdlet,仅通过创建对象即可为我们添加脚本属性。

$FooBarInstance = [FooBar]::new()

$FooBarInstance.Prop1 = 'Egon Spenglar'
Write-host $FooBarInstance.Prop1 -ForegroundColor Green
Run Code Online (Sandbox Code Playgroud)

如果将任何内容传递给它(如本例所示),它将更改_Prop1属性,使其等于您传递给它的任何内容。(在这种情况下为“ Egon Spenglar”)。_Prop1是“隐藏”属性,因此您通常不会在对象上看到它,我们只是使用它来添加此脚本属性来存储和检索信息。

然后,如果您调用不带任何参数的Prop1属性,它将仅返回_Prop1中的值。

$FooBarInstance.Prop1 = 'foo'
Write-host $FooBarInstance.Prop1 -ForegroundColor Green
Run Code Online (Sandbox Code Playgroud)

作为一个示例,说明为什么您可能想要执行类似的操作,在“ Add-Member” cmdlet中添加了一些逻辑,以检查是否传递了字符串“ foo”,如果是,则进行传递而是存储“栏”。

第二个示例将返回“ bar”。

  • 现在使用此方法时,通常会创建一个名为_AddPropName()的方法,然后将其添加到任何构造函数中。当您想为一个类构造一堆构造函数时,它会变得更加整洁。 (2认同)