about_Classes_Properties
about_Classes_Properties
PowerShell 클래스의 속성(Property) 을 어떻게 정의하는지 알려 드릴게요. 속성이란 클래스가 담고 있는 데이터 조각을 말해요. 속성은 어떤 타입이든 가질 수 있고, hidden·static 같은 여러 가지 특성(attribute)을 붙일 수도 있어요. 오늘은 기본 선언부터 Update-TypeData로 만드는 고급 속성까지, 예제를 하나씩 따라가며 설명할게요.
본문
Short description
PowerShell 클래스에 속성을 정의하는 방법을 설명해요.
Long description
속성은 클래스의 멤버로, 데이터를 담는 역할을 해요. 속성은 클래스 범위 안에서 변수처럼 선언돼요. 속성은 내장 타입이 될 수도 있고, 다른 클래스의 인스턴스가 될 수도 있어요. 클래스는 속성을 0개 이상 가질 수 있고, 최대 개수 제한도 없어요.
클래스 속성에는 hidden, static 특성을 포함해 원하는 만큼 attribute를 붙일 수 있어요. hidden 특성과 static 특성도 여기에 해당하죠. 속성을 정의할 땐 반드시 타입을 지정해야 하고, 필요하면 기본값도 정해 줄 수 있어요.
Syntax
클래스 속성은 다음 두 가지 문법으로 선언해요.
One-line syntax
[[<attribute>]...] [<property-type>] $<property-name> [= <default-value>]
Multiline syntax
[[<attribute>]...]
[<property-type>]
$<property-name> [= <default-value>]
Examples
Example 1 - Minimal class properties
ExampleProject1 클래스의 속성들은 attribute나 기본값 없이 내장 타입만 사용해요.
class ExampleProject1 {
[string] $Name
[int] $Size
[bool] $Completed
[string] $Assignee
[datetime] $StartDate
[datetime] $EndDate
[datetime] $DueDate
}
[ExampleProject1]::new()
$null -eq ([ExampleProject1]::new()).Name
Name :
Size : 0
Completed : False
StartDate : 1/1/0001 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
True
Name과 Assignee는 문자열 타입이라 기본값이 $null이 돼요. 문자열은 참조 타입(reference type)이기 때문이에요. 나머지 속성들은 값 타입(value type)이라 각 타입의 기본값을 가져요. 속성 기본값에 대해 더 자세히 알고 싶으면 Default property values를 보면 돼요.
Example 2 - Class properties with custom types
ExampleProject2의 속성에는 ExampleProject2 클래스보다 먼저 정의해 둔 사용자 정의 열거형과 클래스가 사용돼요.
enum ProjectState {
NotTriaged
ReadyForWork
Committed
Blocked
InProgress
Done
}
class ProjectAssignee {
[string] $DisplayName
[string] $UserName
[string] ToString() {
return "$($this.DisplayName) ($($this.UserName))"
}
}
class ExampleProject2 {
[string] $Name
[int] $Size
[ProjectState] $State
[ProjectAssignee] $Assignee
[datetime] $StartDate
[datetime] $EndDate
[datetime] $DueDate
}
[ExampleProject2]@{
Name = 'Class Property Documentation'
Size = 8
State = 'InProgress'
Assignee = @{
DisplayName = 'Mikey Lombardi'
UserName = 'michaeltlombardi'
}
StartDate = '2023-10-23'
DueDate = '2023-10-27'
}
Name : Class Property Documentation
Size : 8
State : InProgress
Assignee : Mikey Lombardi (michaeltlombardi)
StartDate : 10/23/2023 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 10/27/2023 12:00:00 AM
Example 3 - Class property with a validation attribute
ExampleProject3 클래스는 Size 속성을 0 이상, 16 이하인 정수로 정의해요. 값의 범위를 제한하기 위해 ValidateRange attribute를 사용했어요.
class ExampleProject3 {
[string] $Name
[ValidateRange(0, 16)] [int] $Size
[bool] $Completed
[string] $Assignee
[datetime] $StartDate
[datetime] $EndDate
[datetime] $DueDate
}
$project = [ExampleProject3]::new()
$project
Name :
Size : 0
Completed : False
Assignee :
StartDate : 1/1/0001 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
ExampleProject3 인스턴스를 만들면 Size는 0으로 시작해요. 허용 범위 안의 값으로 속성을 설정하면 그 값으로 갱신돼요.
$project.Size = 8
$project
Name :
Size : 8
Completed : False
Assignee :
StartDate : 1/1/0001 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
범위를 벗어난 잘못된 값으로 Size를 설정하면 PowerShell이 예외를 던지고 값은 바뀌지 않아요.
$project.Size = 32
$project.Size = -1
$project
SetValueInvocationException:
Line |
1 | $project.Size = 32
| ~~~~~~~~~~~~~~~~~~
| Exception setting "Size": "The 32 argument is greater than the
| maximum allowed range of 16. Supply an argument that is less than
| or equal to 16 and then try the command again."
SetValueInvocationException:
Line |
2 | $project.Size = -1
| ~~~~~~~~~~~~~~~~~~
| Exception setting "Size": "The -1 argument is less than the minimum
| allowed range of 0. Supply an argument that is greater than or
| equal to 0 and then try the command again."
Name :
Size : 8
Completed : False
Assignee :
StartDate : 1/1/0001 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
Example 4 - Class property with an explicit default value
ExampleProject4 클래스는 StartDate 속성의 기본값을 현재 날짜로 정해요.
class ExampleProject4 {
[string] $Name
[int] $Size
[bool] $Completed
[string] $Assignee
[datetime] $StartDate = (Get-Date).Date
[datetime] $EndDate
[datetime] $DueDate
}
[ExampleProject4]::new()
[ExampleProject4]::new().StartDate -eq (Get-Date).Date
Name :
Size : 0
Completed : False
Assignee :
StartDate : 10/23/2023 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
True
Example 5 - Hidden class property
ExampleProject5 클래스의 Guid 속성에는 hidden 키워드가 붙어 있어요. 그래서 Guid 속성은 클래스의 기본 출력에도, Get-Member가 돌려주는 속성 목록에도 나타나지 않아요.
class ExampleProject5 {
[string] $Name
[int] $Size
[bool] $Completed
[string] $Assignee
[datetime] $StartDate
[datetime] $EndDate
[datetime] $DueDate
hidden [string] $Guid = (New-Guid).Guid
}
$project = [ExampleProject5]::new()
"Project GUID: $($project.Guid)"
$project
$project | Get-Member -MemberType Properties | Format-Table
Project GUID: c72cef84-057c-4649-8940-13490dcf72f0
Name :
Size : 0
Completed : False
Assignee :
StartDate : 1/1/0001 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
TypeName: ExampleProject5
Name MemberType Definition
---- ---------- ----------
Assignee Property string Assignee {get;set;}
Completed Property bool Completed {get;set;}
DueDate Property datetime DueDate {get;set;}
EndDate Property datetime EndDate {get;set;}
Name Property string Name {get;set;}
Size Property int Size {get;set;}
StartDate Property datetime StartDate {get;set;}
Example 6 - Static class property
ExampleProject6 클래스는 Projects라는 static 속성에 지금까지 만든 모든 프로젝트 목록을 담아요. 클래스의 기본 생성자는 새 인스턴스를 이 목록에 추가해요.
class ExampleProject6 {
[string] $Name
[int] $Size
[bool] $Completed
[string] $Assignee
[datetime] $StartDate
[datetime] $EndDate
[datetime] $DueDate
hidden [string] $Guid = (New-Guid).Guid
static [ExampleProject6[]] $Projects = @()
ExampleProject6() {
[ExampleProject6]::Projects += $this
}
}
"Project Count: $([ExampleProject6]::Projects.Count)"
$project1 = [ExampleProject6]@{ Name = 'Project_1' }
$project2 = [ExampleProject6]@{ Name = 'Project_2' }
[ExampleProject6]::Projects | Select-Object -Property Name, Guid
Project Count: 0
Name Guid
---- ----
Project_1 75e7c8a0-f8d1-433a-a5be-fd7249494694
Project_2 6c501be4-e68c-4df5-8fce-e49dd8366afe
Example 7 - Defining a property in the constructor
ExampleProject7 클래스는 static 클래스 생성자에서 Update-TypeData cmdlet으로 Duration이라는 script 속성을 정의해요. PowerShell 클래스의 고급 속성을 정의하는 방법은 Update-TypeData나 Add-Member cmdlet을 쓰는 것뿐이에요.
Duration 속성은 StartDate와 EndDate가 모두 설정되어 있고 StartDate가 EndDate보다 이전일 때만 값을 돌려줘요. 그 조건이 아니면 $null을 반환해요.
class ExampleProject7 {
[string] $Name
[int] $Size
[bool] $Completed
[string] $Assignee
[datetime] $StartDate
[datetime] $EndDate
[datetime] $DueDate
static [hashtable[]] $MemberDefinitions = @(
@{
MemberName = 'Duration'
MemberType = 'ScriptProperty'
Value = {
[datetime]$UnsetDate = 0
$StartNotSet = $this.StartDate -eq $UnsetDate
$EndNotSet = $this.EndDate -eq $UnsetDate
$StartAfterEnd = $this.StartDate -gt $this.EndDate
if ($StartNotSet -or $EndNotSet -or $StartAfterEnd) {
return $null
}
return $this.EndDate - $this.StartDate
}
}
)
static ExampleProject7() {
$TypeName = [ExampleProject7].Name
foreach ($Definition in [ExampleProject7]::MemberDefinitions) {
Update-TypeData -TypeName $TypeName @Definition
}
}
ExampleProject7() {}
ExampleProject7([string]$Name) {
$this.Name = $Name
}
}
$Project = [ExampleProject7]::new()
$Project
$null -eq $Project.Duration
Duration :
Name :
Size : 0
Completed : False
Assignee :
StartDate : 1/1/0001 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
True
ExampleProject7 인스턴스의 기본 보기에는 duration이 포함돼요. 여기서는 StartDate와 EndDate가 설정되어 있지 않으니 Duration 속성이 $null이에요.
$Project.StartDate = '2023-01-01'
$Project.EndDate = '2023-01-08'
$Project
Duration : 7.00:00:00
Name :
Size : 0
Completed : False
Assignee :
StartDate : 1/1/2023 12:00:00 AM
EndDate : 1/8/2023 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
속성들이 올바르게 설정되면 Duration 속성은 프로젝트가 진행된 기간을 나타내는 timespan을 돌려줘요.
Default property values
모든 클래스 속성에는 속성 타입에 따라 암시적인 기본값이 있어요.
속성이 문자열이나 객체 같은 참조 타입이라면 암시적 기본값은 $null이에요. 숫자, 불리언, 열거형 같은 값 타입이라면 타입에 따라 기본값이 달라져요:
- 정수·부동소수점 같은 숫자 타입은 기본값이
0이에요. - 불리언 값의 기본값은
$false예요. - 열거형의 기본값은
0이에요. 열거형에0에 해당하는 이름이 정의되어 있지 않아도요.
.NET에서 기본값에 대해 더 알고 싶으면 Default values of C# types (C# reference) 문서를 보면 돼요.
속성에 명시적인 기본값을 정하고 싶다면, 속성을 선언할 때 기본값을 대입해 주면 돼요.
예를 들어, ProjectTask 클래스 정의에서 Guid 속성의 기본값을 명시해서, 새 인스턴스마다 무작위 GUID를 할당하도록 만들 수 있어요.
class ProjectTask {
[string] $Name
[string] $Description
[string] $Guid = (New-Guid).Guid
}
[ProjectTask]::new()
Name Description Guid
---- ----------- ----
aa96350c-358d-465c-96d1-a49949219eec
hidden 속성과 static 속성에도 기본값을 줄 수 있어요.
Hidden properties
클래스 속성을 hidden 키워드로 선언하면 숨길 수 있어요. hidden 속성은 다음 특징이 있어요.
- 클래스의 기본 출력에 포함되지 않아요.
Get-Membercmdlet이 돌려주는 클래스 멤버 목록에 포함되지 않아요.Get-Member로 hidden 속성을 보려면Force매개 변수를 쓰면 돼요.- 탭 완성이나 IntelliSense에 표시되지 않아요. 단, hidden 속성을 정의한 클래스 안에서 완성이 일어나는 경우는 예외예요.
- 클래스의 공개 멤버예요. 접근하고 수정할 수 있어요. 속성을 숨기는 것은 private으로 만드는 게 아니에요. 위에서 설명한 대로 표시만 숨기는 것뿐이에요.
hidden 키워드에 대해 더 자세히 알고 싶으면 about_Hidden 문서를 보면 돼요.
Static properties
static 키워드로 속성을 선언하면, 인스턴스가 아니라 클래스 자체에 속하는 속성으로 정의할 수 있어요. static 클래스 속성은 다음 특징이 있어요.
- 클래스 인스턴스화와 무관하게 항상 사용할 수 있어요.
- 클래스의 모든 인스턴스에서 공유돼요.
- 항상 사용 가능해요.
- 수정 가능해요. static 속성은 업데이트할 수 있고, 기본적으로 불변(immutable)이 아니에요.
- 세션 전체 동안 유지돼요.
중요
PowerShell에서 정의한 클래스의 static 속성은 불변이 아니에요. static 속성의 타입과 attribute가 허용하는 어떤 유효한 값으로든 덮어쓸 수 있어요.
Derived class properties
클래스가 기본 클래스에서 파생되면 기본 클래스의 속성을 상속받아요. 기본 클래스에 정의된 모든 속성(hidden 속성 포함)은 파생 클래스에서도 사용할 수 있어요.
파생 클래스는 클래스 정의에서 속성을 다시 정의해 상속받은 속성을 재정의(override)할 수 있어요. 파생 클래스의 속성은 재정의된 타입과 기본값(있으면)을 사용해요. 상속받은 속성이 기본값을 정의했는데 재정의한 속성에는 기본값이 없다면, 상속받은 속성은 기본값이 없어져요.
파생 클래스가 static 속성을 재정의하지 않으면, 파생 클래스를 통해 그 static 속성에 접근하면 기본 클래스의 static 속성에 접근하게 돼요. 파생 클래스를 통해 속성값을 수정하면 기본 클래스에 있는 값이 바뀌어요. static 속성을 재정의하지 않은 다른 파생 클래스들도 기본 클래스의 속성값을 사용해요. 같은 기본 클래스에서 파생된 클래스들에서, 상속받은 static 속성의 값을 재정의하지 않는 클래스가 그 값을 바꾸면 의도하지 않은 영향을 줄 수 있어요.
다음 예제는 파생 클래스에서 static 속성과 인스턴스 속성이 어떻게 동작하는지 보여 줘요.
class BaseClass {
static [string] $StaticProperty = 'Static'
[string] $InstanceProperty = 'Instance'
}
class DerivedClassA : BaseClass {}
class DerivedClassB : BaseClass {}
class DerivedClassC : DerivedClassB {
[string] $InstanceProperty
}
class DerivedClassD : BaseClass {
static [string] $StaticProperty = 'Override'
[string] $InstanceProperty = 'Override'
}
"Base instance => $([BaseClass]::new().InstanceProperty)"
"Derived instance A => $([DerivedClassA]::new().InstanceProperty)"
"Derived instance B => $([DerivedClassB]::new().InstanceProperty)"
"Derived instance C => $([DerivedClassC]::new().InstanceProperty)"
"Derived instance D => $([DerivedClassD]::new().InstanceProperty)"
Base instance => Instance
Derived instance A => Instance
Derived instance B => Instance
Derived instance C =>
Derived instance D => Override
DerivedClassC의 InstanceProperty는 빈 문자열이에요. 클래스가 속성을 기본값 없이 재정의했기 때문이에요. DerivedClassD는 그 문자열을 기본값으로 속성을 재정의했으니 값이 Override예요.
"Base static => $([BaseClass]::StaticProperty)"
"Derived static A => $([DerivedClassA]::StaticProperty)"
"Derived static B => $([DerivedClassB]::StaticProperty)"
"Derived static C => $([DerivedClassC]::StaticProperty)"
"Derived static D => $([DerivedClassD]::StaticProperty)"
Base static => Static
Derived static A => Static
Derived static B => Static
Derived static C => Static
Derived static D => Override
DerivedClassD를 제외하면 파생 클래스들의 static 속성값은 기본 클래스와 같아요. 이는 속성을 재정의하지 않았기 때문이에요. DerivedClassB가 아닌 BaseClass에서 직접 상속받는 DerivedClassC에도 그대로 적용돼요.
[DerivedClassA]::StaticProperty = 'Updated from A'
"Base static => $([BaseClass]::StaticProperty)"
"Derived static A => $([DerivedClassA]::StaticProperty)"
"Derived static B => $([DerivedClassB]::StaticProperty)"
"Derived static C => $([DerivedClassC]::StaticProperty)"
"Derived static D => $([DerivedClassD]::StaticProperty)"
Base static => Updated from A
Derived static A => Updated from A
Derived static B => Updated from A
Derived static C => Updated from A
Derived static D => Override
DerivedClassA를 통해 StaticProperty에 접근해 값을 바꾸면, 변경된 값이 DerivedClassD를 제외한 모든 클래스에 영향을 줘요.
포괄적인 예제를 포함한 클래스 상속에 대해 더 알고 싶으면 about_Classes_Inheritance 문서를 보면 돼요.
Use property attributes
PowerShell에는 데이터 타입 정보를 보강하고 속성에 할당되는 데이터를 검증하는 여러 attribute 클래스가 있어요. 검증 attribute를 쓰면 속성에 주어지는 값이 정의된 요구 사항을 충족하는지 확인할 수 있어요. 검증은 값이 할당되는 순간에 실행돼요.
사용 가능한 attribute에 대해 더 자세히 알고 싶으면 about_Functions_Advanced_Parameters 문서를 보면 돼요.
Define instance properties with Update-TypeData
클래스 정의에서 직접 속성을 선언하는 방법 외에도, static 생성자에서 Update-TypeData cmdlet으로 클래스 인스턴스의 속성을 정의할 수 있어요.
이 스니펫을 패턴의 출발점으로 사용하면 돼요. 꺾쇠괄호 안의 자리 표시자(placeholder) 텍스트는 필요에 따라 바꾸면 돼요.
class <ClassName> {
static [hashtable[]] $MemberDefinitions = @(
@{
MemberName = '<PropertyName>'
MemberType = '<PropertyType>'
Value = <ValueDefinition>
}
)
static <ClassName>() {
$TypeName = [<ClassName>].Name
foreach ($Definition in [<ClassName>]::MemberDefinitions) {
Update-TypeData -TypeName $TypeName @Definition
}
}
}
팁
Add-Member cmdlet도 non-static 생성자에서 클래스에 속성과 메서드를 추가할 수 있어요. 하지만 이 cmdlet은 생성자가 호출될 때마다 실행돼요. static 생성자에서 Update-TypeData를 쓰면 클래스에 멤버를 추가하는 코드가 세션에서 한 번만 실행되도록 보장할 수 있어요.
읽기 전용 속성처럼 Update-TypeData로는 정의할 수 없는 경우에만 non-static 생성자에서 클래스에 속성을 추가하세요.
Defining alias properties
Alias attribute는 클래스 속성 선언에 사용하면 효과가 없어요. PowerShell은 이 attribute를 cmdlet·매개 변수·함수 이름의 별칭을 정의할 때만 사용해요.
클래스 속성의 별칭을 정의하려면 AliasProperty MemberType과 함께 Update-TypeData를 사용하면 돼요.
예를 들어, OperablePair 클래스 정의는 x와 y 두 개의 정수 속성을 정의하고 각각 LeftHandSide, RightHandSide 별칭을 붙여요.
class OperablePair {
[int] $x
[int] $y
static [hashtable[]] $MemberDefinitions = @(
@{
MemberType = 'AliasProperty'
MemberName = 'LeftHandSide'
Value = 'x'
}
@{
MemberType = 'AliasProperty'
MemberName = 'RightHandSide'
Value = 'y'
}
)
static OperablePair() {
$TypeName = [OperablePair].Name
foreach ($Definition in [OperablePair]::MemberDefinitions) {
Update-TypeData -TypeName $TypeName @Definition
}
}
OperablePair() {}
OperablePair([int]$x, [int]$y) {
$this.x = $x
$this.y = $y
}
# Math methods for the pair of values
[int] GetSum() { return $this.x + $this.y }
[int] GetProduct() { return $this.x * $this.y }
[int] GetDifference() { return $this.x - $this.y }
[float] GetQuotient() { return $this.x / $this.y }
[int] GetModulus() { return $this.x % $this.y }
}
별칭을 정의해 두면, 사용자는 두 이름 중 아무거나 써서 속성에 접근할 수 있어요.
$pair = [OperablePair]@{ x = 8 ; RightHandSide = 3 }
"$($pair.x) % $($pair.y) = $($pair.GetModulus())"
$pair.LeftHandSide = 3
$pair.RightHandSide = 2
"$($pair.x) x $($pair.y) = $($pair.GetProduct())"
8 % 3 = 2
3 x 2 = 6
Defining calculated properties
다른 속성들의 값을 참조해서 계산하는 속성을 정의하려면 ScriptProperty MemberType과 함께 Update-TypeData cmdlet을 사용하면 돼요.
예를 들어, Budget 클래스 정의는 Expenses와 Revenues 속성을 부동소수점 배열로 정의해요. 여기에 Update-TypeData cmdlet으로 총 지출(outgo), 총 수입, 순이익을 계산하는 속성을 정의했어요.
class Budget {
[float[]] $Expenses
[float[]] $Revenues
static [hashtable[]] $MemberDefinitions = @(
@{
MemberType = 'ScriptProperty'
MemberName = 'TotalExpenses'
Value = { ($this.Expenses | Measure-Object -Sum).Sum }
}
@{
MemberType = 'ScriptProperty'
MemberName = 'TotalRevenues'
Value = { ($this.Revenues | Measure-Object -Sum).Sum }
}
@{
MemberType = 'ScriptProperty'
MemberName = 'NetIncome'
Value = { $this.TotalRevenues - $this.TotalExpenses }
}
)
static Budget() {
$TypeName = [Budget].Name
foreach ($Definition in [Budget]::MemberDefinitions) {
Update-TypeData -TypeName $TypeName @Definition
}
}
Budget() {}
Budget($Expenses, $Revenues) {
$this.Expenses = $Expenses
$this.Revenues = $Revenues
}
}
[Budget]::new()
[Budget]@{
Expenses = @(2500, 1931, 3700)
Revenues = @(2400, 2100, 4150)
}
TotalExpenses : 0
TotalRevenues : 0
NetIncome : 0
Expenses :
Revenues :
TotalExpenses : 8131
TotalRevenues : 8650
NetIncome : 519
Expenses : {2500, 1931, 3700}
Revenues : {2400, 2100, 4150}
Defining properties with custom get and set logic
PowerShell 클래스 속성은 getter·setter 로직을 직접 정의할 수 없어요. hidden 키워드로 backing 속성을 정의하고, Update-TypeData로 값을 가져오고 설정하는 커스텀 로직을 가진 보이는 속성을 정의하면 이 기능을 비슷하게 흉내낼 수 있어요.
관례적으로 hidden backing 속성 이름은 밑줄 접두사를 붙이고 camel casing을 사용해요. 예를 들어 TaskCount 대신 hidden backing 속성 이름을 _taskCount로 지어요.
이 예제에서 ProjectSize 클래스는 _value라는 이름의 hidden 정수 속성을 정의해요. 그리고 Value를 getter·setter 로직이 있는 ScriptProperty로 정의해요. setter 스크립트블록은 프로젝트 크기의 문자열 표현을 올바른 크기로 변환하는 역할을 해요.
class ProjectSize {
hidden [ValidateSet(0, 1, 2, 3)] [int] $_value
static [hashtable[]] $MemberDefinitions = @(
@{
MemberType = 'ScriptProperty'
MemberName = 'Value'
Value = { $this._value } # Getter
SecondValue = { # Setter
$ProposedValue = $args[0]
if ($ProposedValue -is [string]) {
switch ($ProposedValue) {
'Small' { $this._value = 1 ; break }
'Medium' { $this._value = 2 ; break }
'Large' { $this._value = 3 ; break }
default { throw "Unknown size '$ProposedValue'" }
}
} else {
$this._value = $ProposedValue
}
}
}
)
static ProjectSize() {
$TypeName = [ProjectSize].Name
foreach ($Definition in [ProjectSize]::MemberDefinitions) {
Update-TypeData -TypeName $TypeName @Definition
}
}
ProjectSize() {}
ProjectSize([int]$Size) { $this.Value = $Size }
ProjectSize([string]$Size) { $this.Value = $Size }
[string] ToString() {
$Output = switch ($this._value) {
1 { 'Small' }
2 { 'Medium' }
3 { 'Large' }
default { 'Undefined' }
}
return $Output
}
}
커스텀 getter와 setter를 정의해 두면, Value 속성을 정수나 문자열 어느 쪽으로든 설정할 수 있어요.
$size = [ProjectSize]::new()
"The initial size is: $($size._value), $size"
$size.Value = 1
"The defined size is: $($size._value), $size"
$Size.Value += 1
"The updated size is: $($size._value), $size"
$Size.Value = 'Large'
"The final size is: $($size._value), $size"
The initial size is: 0, Undefined
The defined size is: 1, Small
The updated size is: 2, Medium
The final size is: 3, Large
Limitations
PowerShell 클래스 속성에는 다음 제약이 있어요.
- Static 속성은 항상 변경 가능해요. PowerShell 클래스는 불변(immutable)인 static 속성을 정의할 수 없어요.
- 해결 방법: 없음.
ValidateScriptattribute는 클래스 속성 attribute 인수가 상수여야 하기 때문에 사용할 수 없어요.- 해결 방법:
ValidateArgumentsAttribute타입에서 상속받은 클래스를 정의하고 그 attribute를 사용하세요.
- 해결 방법:
- 직접 선언한 속성은 커스텀 getter·setter 구현을 정의할 수 없어요.
- 해결 방법: hidden 속성을 정의하고
Update-TypeData로 보이는 getter·setter 로직을 정의하세요.
- 해결 방법: hidden 속성을 정의하고
- 속성은
Aliasattribute를 사용할 수 없어요. 그 attribute는 매개 변수·cmdlet·함수에만 적용돼요.- 해결 방법: 클래스 생성자에서
Update-TypeDatacmdlet으로 별칭을 정의하세요.
- 해결 방법: 클래스 생성자에서
- PowerShell 클래스를
ConvertTo-Jsoncmdlet으로 JSON으로 변환하면, 출력 JSON에 모든 hidden 속성과 그 값이 포함돼요.- 해결 방법: 없음.