C#] Properties vs Fields 차이점
Field란?
class나 struct 바로 아래에 선언된 변수이다. public, private, protected, internal, protected internal, private protected가 될 수 있다.
private int _age;
private 이기 때문에, class 내부에서만 접근할 수 있다.
fields는 일반적으로 backing store, backing field 용도로 사용한다. field를 private로 선언하고 public property로 접근해서 사용한다.
public int Age
{
get { return _age; }
set { _age = value; }
}
Person class의 생성에 따른 실행을 살펴보자.
public class Person
{
private string _name = "John Doe";
public Person()
{
Console.WriteLine(_name);
_name = "Jane Doe";
}
public void UpdateName(string name)
{
Console.WriteLine(_name);
_name = name;
Console.WriteLine(_name);
}
}
선언에서 _name field 값을 설정하고, constructor에서 수정한다. 마지막으로 UpdateName()함수에서 추가로 수정한다.
var person = new Person();
person.UpdateName("Sam Doe");
// output
// John Doe
// Jane Doe
// Sam Doe
Fields Type
- readonly : field를 readonly로 선언할 수 있다. 이는 선언시나 constructor에서만 값을 할당할 수 있다는 뜻이다. _name을 readonly로 변경하면 UpdateName() 함수에서 컴파일 에러가 발생한다.
- static : fields를 static으로 선언할 수 있다. 전역변수처럼 type 초기화 없이 접근할 수 있다. 모든 class instance에서 하나의 값을 공유한다.
- readonly, static : field는 동시에 static, readonly일 수 있다. static readonly는 constants와 유사하다. 하지만 constants와 다르게 compile time이 아닌 runtime에 값이 정해진다.
public class Person
{
public static int Age;
private string _name = "John Doe";
}
Person object의 초기화 없이 Age field 접근이 가능하다.
Person.Age = 19;
- required : object 생성 시 초기화되어야 한다.
required field를 초기화하지 않았기 때문에 compile error가 발생한다.
Program p = new Program { b = 1 };
이렇게 수정해야 한다.
Property란?
properties는 getter, setter 함수를 통해 제한된 접근을 제공하여 private fields를 encapsulate하는 방식이다. get accessor로 property value를 얻고, set accessor로 property에 value를 할당한다. set accessor는 value라는 암시적 parameter를 갖는다.
public int Age
{
get { return _age; }
set { _age = value; }
}
public string Name { get; set; }
properties는 자동으로 생성된 private backing field를 생성하며, get/set accessor를 위한 기본 구현을 제공한다.
Property type
위의 properties는 read-write properties이다. get accessor만 갖으므로 read-only properties를 만들수도 있고, set accessor만 갖으므로 write-only properties를 만들 수도 있다.
public class Configuration
{
private string _secretKey = string.Empty;
public string SecretKey
{
set
{
_secretKey = $"**{value}**";
}
}
public string MaskedSecretKey
{
get { return _secretKey; }
}
}
Init Only Properties
C# 9.0부터 init accessor가 도입되었다. object 생성 시, property의 초기값을 설정하고 이후에 수정할 수 없다.
public class Rectangle
{
public double Width { get; init; }
public double Height { get; init; }
}
var newRectangle = new Rectangle { Width = 10, Height = 5 };
이후에 값을 수정하려고 하면 compile error가 발생한다.
Static Properties
public static double ScalingFactor { get; set; } = 1.0;
Virtual, Abstract Properties
virtual properties는 자식 클래스에서 override 키워드를 사용하여 override할 수 있다.
abstract class에서 abstract property를 선언할 수 있다. 자식클래스에서 구현한다.
Property와 Field의 차이점
큰 차이점은 접근성, 캡슐화, 제어 레벨이다.
접근성, 직접 접근
Fields는 class바깥에서 직접 접근을 할 수 있으며, 종종 private, public, protected 키워드와 함께 선언된다. 캡슐화 mechanism이 부족하다.
Properties는 data를 캡슈ㅠ화하고 accessors를 통해 제어한다. 조금 더 통제적이다.
캡슐화
public access modifier와 선언된 fields는 상속보호나 validation 없이 데이터가 노출될 수 있다.
properties는 어떻게 data를 접근하고 수정할지 제어할 수 있다. 예를들어, validation logic으로 원하는 데이터만 set할 수 있다.
Get, Set Accessors 사용법
public double Width
{
get => _width;
init
{
if (value < 0)
throw new ArgumentException("A Rectangle can't have negative width",
nameof(value));
_width = value;
}
}
언제 사용해야 하는가?
큰 차이점 중 하나가 데이터 캡슐화라면, 다른 하나는 데이터를 읽거나 쓸때 수행하는 계산 또는 유효성 검증이다. 둘 다 검토해야 할 사항이다.
- 캡슐화
Fields는 data에 직접 접근할 수 있기 때문에, 데이터 접근성이 중요할때 사용하기 알맞다. 단순한 domain model이나 값에 대한 추가 검증이 필요없을 때 사용한다. 클래스 외부에서 호출할 때 object 내부 상태를 수정할 수 있다.
Properties는 접근 제어를 할 수 있고, 추가 검증과 계산기 가능하다. object 내부 상태가 유지된다.
- 계산된 value
온도와 같은 class modeling에서 내부적으로 Kelvin으로 저장한다. 그 다음에 Fahrenheir, Celsius값으로 get, set할 수 있게 한다. 이러한 것은 Field로는 할 수 없다.
결론
원하는 제어 레벨과 캡슐화에 따라 둘 중 선택할 수 있다.