5

I have a class where there are properties on the class, but I only want to be able to set their values internally, but allow a public get accessor on it. Since there is no PS equivalent in classes like this in C#:

public string PropertyName {
   get;
   private set;
}

I've looked at implementing the following workaround on my class so the "private" members remain hidden with a public accessor for the property:

class MyClass {
  hidden [string]$_PropertyName
  
  MyClass( $propertyValue ) {
    $this._PropertyName = $PropertyValue
    $this | Add-Member -ScriptProperty -Name 'PropertyName' -Value {
      return $this.$_PropertyName
    } -SecondValue {
      throw "Cannot write value to a readonly property"
    }
  }
}

This works well and does what I want, but this class also has a couple of static properties I want to do the same thing for from its static constructor. While the code above does work for setting the property on the class type itself (substituting [MyClass] for $this), there is a small quirk that makes the syntax for accessing the "readonly" property inconsistent with normally accessing static members:

hidden static [string]$_StaticProperty = 'someValue'

static MyClass() {
  [MyClass] | Add-Member -ScriptProperty StaticProperty -Value {
    return [MyClass]::$_StaticProperty
  }
}

I can access StaticProperty but only as if it were an instance member:

[MyClass]::StaticProperty # ==> $null
[MyClass].StaticProperty # ==> someValue

Is there a way to add a static member to a type using Add-Member so I can keep the accessor syntax consistent?

1 Answer 1

4

Is there a way to add a static member to a type using Add-Member so I can keep the accessor syntax consistent?

No

Add-Member was designed to allow user to add synthetic ETS properties to instance objects - at a time long before anyone was thinking about adding the class keyword to the language grammar.

Put another way, "static members" carry zero meaning in the context of ETS, because ETS members are tied to the identity of already-instantiated objects.

If you want class member behavior as found in C#, use C#:

Add-Type @'
public class MyClass
{
  static MyClass()
  {
    MyClass.StaticProperty = "some value";
  }

  public static string StaticProperty { get; private set; }
}
'@

# Use [MyClass]::StaticProperty
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the answer. I've been trying to use PowerShell classes for some things instead of PSCustomObjects as proper classes make sense for some of the work I'm doing, but it's discouraging finding how limited PS classes are when other .NET languages carry its full set of features. Starting to think I should just start writing classes in C# as PS classes basically just feel like defining structs in practice.
@BendertheGreatest Not sure structs are the right analogy here (PowerShell classes are true reference types), but the big question is what are you trying to achieve? The example in your question is quite generic, but I suspect you might be able to substitute a module-scoped read-only variable for the static property in real life
This example is more of a case of practice with classes in PowerShell to get away from compiling C# code with Add-Type in production code, seeing what can and can't be done with them. A readonly property works if you only need to set the value once, but not if the object must change later on. A method works but then why use Properties at all? This also shows what you have to do to control what a getter/setter does in general. There is interest in defining getter/setter behavior, so I don't think I'm off base wanting PS to support this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.