Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
902 views
in Technique[技术] by (71.8m points)

powershell - Programmatically Setting Public Property in Class Ctor

I want to programmatically set a public property within a class' constructor in PowerShell V5.0. The test class has many public properties that are to be filled in depending on the object passed to the class' constructor (lovingly referred to as '$something')

I thought it'd save a lot of code if I created an array of public property names which was accessible and iterate through them, as the setting the value of the public properties is just calling the same method on the $something object passed to it.

Tried using the Set-Variable cmdlet on every scope (I thought it'd be local scope). It could be done manually setting each public property in the constructor, but I'd love to be able to shorten it if possible.

    Class TestClass
    {
        [STRING]$PublicProperty
        [STRING]$PublicProperty1
        ... ... ... #Loads more properties
        [STRING]$PublicProperty50
        #An array that contains name for public properties
        [ARRAY]$ArrayOfPublicProperties = @("PublicProperty", "PublicProperty1"...)

        TestClass($something)
        {
            foreach ($property in $this.ArrayOfPublicProperties)
            {
                Set-Variable -Name "$($property.Name)" -Scope Local -Value $($something.GetValue(#blablabla))
            }
        }
    }

I expect to be able to iterate through the public array (it's gross code, but it works for the situation I'm in and I don't know enough to think of any other ways) and set the variable using the Set-Variable cmdlet. Instead it doesn't set anything. I'm sure I've done something similar in the past, programmatically creating and setting variables etc... idk.

Pls to help

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Set-Variable only works with regular variables, not with properties.

You must use reflection via .psobject.properties, which also obviates the need for the $ArrayOfPublicProperties helper property:

Class TestClass
{
    [string]$PublicProperty
    [string]$PublicProperty1
    # ...

    TestClass($something)
    {
        # Loop over all properties of this class.
        foreach ($prop in $this.psobject.Properties)
        {
          $prop.Value = $something.GetValue(#blablabla)
        }
    }
}

Note, however, that PowerShell conveniently allows constructing and initializing objects by a way of a cast from a hashtable or (custom) object that have matching properties.

Caveats: For this to work:

  • the class must either have NO constructor (i.e., implicitly support only the parameter-less default constructor),
  • OR, if there are constructors:

    • a parameter-less constructor must exist too.
      • Symptom, if that condition isn't met: a type-conversion error: Cannot convert ... to type ...
    • AND there's not also a single-argument constructor (implicitly) typed [object] or [hashtable] (with a hashtable cast argument, [psobject] / [pscustomobject] is fine, however).
      • Symptom, if that condition isn't met: the single-argument constructor is called.
  • The set of property names of the input hashtable / object must be a subset of the target class' properties; in other words: the input object mustn't contain properties that aren't also present in the target class, but not all target-class properties must be present.

Applied to your example (note that there's no longer an explicit constructor, because the original constructor, TestClass($something), would defeat the feature, due to $something being implicitly [object]- typed):

Class TestClass
{
    [string]$PublicProperty
    [string]$PublicProperty1
    # ...
    # Note: NO (explicit) constructor is defined.
}

# Construct a [TestClass] instance and initialize its properties
# from a hashtable, using a cast.
[TestClass] @{ PublicProperty = 'p0'; PublicProperty1 = 'p1'}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

56.6k users

...