C# 개념 (2)-속성 (Properties)

C# 개념 (2)-속성 (Properties)

속성 (Properties)

1
2
3
4
5
6
public class Person
{
public string FirstName;
// remaining implementation removed from listing
}

1
2
3
4
5
6
7
public class Person
{
public string FirstName { get; set; }

// remaining implementation removed from listing
}

위에 표시된 구분은 자동 속성 구문 입니다. 컴파일러가 get및 set 접근자의 본문을 구현함

FirstName 필드에 초기 값을 null 대신 빈문자열로 설정하려면 아래와 같이 한다.

1
2
3
4
5
6
7
8

public class Person
{
public string FirstName { get; set; } = string.Empty;

// remaining implementation removed from listing
}

특성 초기화는 읽기 전용 속성에 가장 유용하다.

아래 처럼 직접 정의도 가능하다.

1
2
3
4
5
6
7
8
9
10
public class Person
{
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
private string firstName;
// remaining implementation removed from listing
}

속성 구현이 단일식인 경우 getter또는 setter에 식 본문 맴버로 사용할수 있다.

1
2
3
4
5
6
7
8
9
10
public class Person
{
public string FirstName
{
get => firstName;
set => firstName = value;
}
private string firstName;
// remaining implementation removed from listing
}

유효성 검사

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Person
{
public string FirstName
{
get => firstName;
set
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("First name must not be blank");
firstName = value;
}
}
private string firstName;
// remaining implementation removed from listing
}

아래는 좀더 간소화 버전

1
2
3
4
5
6
7
8
9
10
public class Person
{
public string FirstName
{
get => firstName;
set => firstName = (!string.IsNullOrWhiteSpace(value)) ? value : throw new ArgumentException("First name must not be blank");
}
private string firstName;
// remaining implementation removed from listing
}

읽기 전용

1
2
3
4
5
6
public class Person
{
public string FirstName { get; private set; }

// remaining implementation removed from listing
}

위 방법은 거의 사용하지 않음

1
2
3
4
5
6
7
8
public class Person
{
public Person(string firstName) => this.FirstName = firstName;

public string FirstName { get; }

// remaining implementation removed from listing
}

위처럼 set을 만들지 않음

읽기 전용 속성은 노출되는 컬렉션을 초기화 하는데 주로 사용됨

1
2
3
4
public class Measurements
{
public ICollection<DataPoint> points { get; } = new List<DataPoint>();
}

계산된 속성

1
2
3
4
5
6
7
8
public class Person
{
public string FirstName { get; set; }

public string LastName { get; set; }

public string FullName { get { return $"{FirstName} {LastName}"; } }
}

식을 이용해서 축약해서 보면

1
2
3
4
5
6
7
8
public class Person
{
public string FirstName { get; set; }

public string LastName { get; set; }

public string FullName => $"{FirstName} {LastName}";
}

캐쉬된 평가 속성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Person
{
public string FirstName { get; set; }

public string LastName { get; set; }

private string fullName;
public string FullName
{
get
{
if (fullName == null)
fullName = $"{FirstName} {LastName}";
return fullName;
}
}
}

위에 간단한 버그가 있는데 FirstName이나 LastName을 갱신해도 fullName 속성이 갱신이 되지 않는다 간단하게 수정해서 보면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Person
{
private string firstName;
public string FirstName
{
get => firstName;
set
{
firstName = value;
fullName = null;
}
}

private string lastName;
public string LastName
{
get => lastName;
set
{
lastName = value;
fullName = null;
}
}

private string fullName;
public string FullName
{
get
{
if (fullName == null)
fullName = $"{FirstName} {LastName}";
return fullName;
}
}
}

자동 구현 속성에 특성 연결

C# 7.3부터 필드 특성은 자동 구현된 속성의 컴파일러에서 생성된 지원 필드에 연결할수 있다.

다음 예제와 같이 특성에 field: 지정자를 사용하여 Id 속성의 지원 필드에 NonSerializedAttribute를 연결할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
public class Person
{
public string FirstName { get; set; }

public string LastName { get; set; }

[field:NonSerialized]
public int Id { get; set; }

public string FullName => $"{FirstName} {LastName}";
}

INotifyPropertyChanged 구현

구성 데이터가 바꼈을때 이벤트 처리를 하는 방법을 보여준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Person : INotifyPropertyChanged
{
public string FirstName
{
get => firstName;
set
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("First name must not be blank");
if (value != firstName)
{
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(FirstName)));
}
firstName = value;
}
}
private string firstName;

public event PropertyChangedEventHandler PropertyChanged;
// remaining implementation removed from listing
}

참조