참고 자료: MS Document
- C#이 생각보다 자료가 많이 없어서 그냥 공식문서 보고 정리하려고 한다.
일단은공식문서
상의 구조를 따라가려고 하는데 내용은 내 맘대로 써질 예정- 본질이 iOS 개발자라 많이 비교하면서 학습을 진행할 예정이다.
- @>--- 이런 기호와 함께 '기울임', '작게' 표시 되면 개인적인 생각이다.- 당연 이건 다른 언어를 했던 사람들이 C# 공부시 그나마 조금 편하라고 만들어 보는거지 아예 코드 짜는 사람이 처음이라면 이해 안될 수 있는다.
- 이해 안되는건 뒤에 나올 내용이 앞에 나와서 그러는거니까 첨보는 단어면 일단 넘어가면 뒤에 다시 나온다.
@>--- 일단 레코드라는건 swift에서 들어보지 못한 타입이다. 그러므로 내용을 보며 비슷한걸 찾아보겠다.
특별한
구문과 동작을 제공하는 클래스 또는
구조체 이다.record
한정자는 주 역할이 데이터를 저장하는 형식에 유용한 멤버를 합성하게 한다.값 같음
여부에 따라 달라지는 데이터 모델을 정의하려는 경우변경할 수 없는
개체의 형식을 정의하려고 할때값 같음
은 형식이 일치
하고 모든
속성 및 필드 값
이 동일하다고 비교되는 레코드 형식의 두 변수가 같다는 것
을 의미한다.참조 타입들
의 경우 같음
에서 값 같음
이 구현되지 않는 한 기본적으로 참조 같음
을 의미한다.참조
하는 경우 같다.변경할 수 없는 형식
은 인스턴스화 된 후 개체의 속성 또는 필드 값을 변경
하는 것을 방지
하는 형식이다.유용할 수
있다.클래스 또는 구조체 선언하고 인스터스화하는 동일 구문을 레코드와 함께 사용 가능하다.
class와 struct 키워드를 record
와 record struct
로 대체해 사용한다.
상속을 표현하기 위한 구문은 레코드 클래스에서 동일
하게 지원한다.
레코드가 클래스와 다른
점은 다음과 같다.
1] 기본 생성자에서 위치 매개 변수 사용해 변경할 수 없는 속성을 사용해 타입을 만들고 인스턴스화할 수 있다.
이게 무슨말일까?
일단 레코드는
불변
데이터 모델을 쉽게 정의하기 위한 타입이다클래스나 구조체와 달리 레코드는 기본 생성자를 지원하는데 이 생성자에서
위치 매개 변수
를 정의하면, 해당 매개 변수들은 자동으로읽기 전용
속성으로 선언된다.
- 위치 매개 변수 => 클래스 뒤에 입력하는 매개변수 를 의미 -> 예시 코드에서 FirstName, LastName을 의미
public record Person(string FirstName, string LastName); static void Main(string[] args) { Person gildong = new Person("길동", "홍"); }
이렇게 main에서 한거처럼 매개 변수를 통해 해당 속성들에 값을 할당하면 이후에는 값을 변경 할 수 없다.
근데 이게 왜??
- 일단 클래스는 기본적으로 이런 방식의 간결한 정의가 불가능!
- 불변 속성을 가진 클래스를 만들려면 조금 코드가 많이 길어짐..
public class Animal { public string Name { get; } public Animal(string name) { this.Name = name; } }
- 코드가 길어지는건 물론이고, 불변성 유지 위한 추가 작업이 필요
2] 클래스에서 참조
같음 또는 같지 않음을 나타내는 동일한 메서드와 연산자가 레코드에서 값
같음 또는 같지 않음을 나타낸다.
3] with
식을 사용해 선택된 속성에 새 값을 포함하는 변경할 수 없는 개체의 복사본을 만들 수 있다.
with 식?
레코드와 함꼐 도입되었으므로 레코드와 함꼐 보는게 맞음
기존 객체를 기반으로
일부
속성만 변경해새로운
객체를생성
시에 사용
with 식은 기존 객체의 값을
복사
해 새 객체를 생성하면서, 특성 속성의 값만변경
할 수 있도록 해주는 구문
이를 통해
비파괴적 복사
가 가능비파괴적 복사??
- 원본 객체를 변경하지 않고, 그 객체를 기반으로 새 객체를 생성하는것을 의미
- 얕은 복사랑 다른게 없군
- 필요한 변경 사항만 반영된 새 객체를 만들다 보니
불변
객체를 다루거나데이터 무결성 유지
해야 하는 상황에서 중요Person gamdong = gildong with { FirstName = "감동" };
- 장점
- 코드의 간결성
- 안정성 : 원본 변경않으므로 사이드 이펙트 방지
- 유지보수성 : 상태 변이에 따른 버그 발생 가능성을 줄여줌
얕은 복사 & 깊은 복사 (shallow copy & deep copy)
- 얕복: 객체의
필드 값
을 그대로 복사, 주소는 동일 주소를 가짐
with
가 여기에 해당 : 만약 참조 타입 속성의 내부를 변경하면 원본과 복사본 둘다 영향 받을 수 있음- 깊복: 객체의
필드 값
,주소
가 가리키는 객체까지모두 새로
복사클래스에서도 비파괴적 복사 구현
- 클래스에서도 가능하게 할 수 있는데
복제
메서드와init
접근자를 사용하면 된다.static void Main(string[] args) { Animal dog = new Animal("Puppy"); var dog2 = dog.With(p => p.Name = "dog"); } public class Animal { public string Name { get; set; } public Animal(string name) => (Name) = (name); public Animal With(Action<Animal> updater) { var clone = (Animal)this.MemberwiseClone(); updater(clone); return clone; } }
- 이런식으로 하면 얼추 비슷한 동작을 하는걸 클래스에서도 만들 수 있다.
복제 메서드?
- 현재 객테의 상태를 복사해 새 객체를 생성하는 메서드
- 이를 통해 원복 객체를 변경치 않고 일부 속성만 수정된 새로운 객체를 생성 가능함. (위에서 이야기 하던 with 랑 비슷하네)
목적: with식이랑 흡사한 목적
- 비파괴적 복사(얕복)
- 객체 복사
- 변형된 객체 생성
방법: 클래스에서도 비파괴적 복사 구현의 코드 참고
[자기 클래스] [메서드명] (매개변수)
로 구현MemberwiseClone()
이라는 .NET의 제공 메서드를 사용
- 현 객체의 얕복본을 생성
- 내부에 다른 값들을 넣고 다른 방식으로 하고 싶으면 해당 메서드를 알아서 잘 구현 하면 된다.
4] 레코드의 ToString
메서드는 개체 형식 이름과 모든 퍼블릭 속성의 이름과 값을 표시하는 형식 문자열을 만든다
5] 레코드는 다른 레코드
에서 상속
될 수 있다.
없다
레코드 구조체는 컴파일러
가 같음(==)
과 ToString을 위한 메서드를 합성
한다는 점에서 구조체와 다르다.
레코드 구조체 와 구조체의 차이점
1] 동등성 비교
모든
필드의 값을 비교해 동등성을 판단2] ToString 메서드
구조체
전체 이름
을 반환한다.레코드 구조체
자동
으로 해당 메서드를 생성해 형식 이름
과 모든 퍼블릭
필드 또는 속성의 이름
과 값
을 포함한 문자열을 반환한다.public struct Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y) => (X, Y) = (x, y);
}
public record struct PointXY(int X, int Y);
static void Main(string[] args) {
var p1 = new Point(1, 2);
var p3 = new PointXY(3, 4);
Console.WriteLine(p1.ToString());
Console.WriteLine(p3.ToString());
}
// 결과 ----
// LearnMSDoc.Point
// PointXY { X = 3, Y = 4 }
컴파일러가 메서드를 합성한다?
- 컴파일러가 해당 메서드의 코드를 자동으로 생성해준다는 의미로 개발자가 직접 코드를 짤 필요가 없다는 소리이다.
- 코드의 간결성, 일관성 있는동작, 불변 데이터 모델링에 적합한 동작을 만들어준다.
컴파일러는 위치 레코드 구조체에 대한 Deconstruct
메서드를 합성한다.
위치 레코드 구조?
- record struct 를 말하는거 같음
- C# 에서 구조체와 레코드의 특성을 결합한 타입으로
값
타입이며불변성
과값 기반 동등성
을 지원한다.- 매개변수를 사용해 정의되며 컴파일러가 여러 유용한 메서드와 속성을 자동으로 생성해준다.
Deconstruct 메서드?
@>--- record sturct 선언하며 매개변수만 넣을 때 그게 잘 붙는지 그거 해주는거 같음
- 객체의 필드를 개별 변수로
분해
할 수 있게 해주는 메서드이다.- 이 메서드를 사용하면 튜플 분해 구문을 통해 객체의 속성 값을 손쉽게 추출할 수 있다.
public void Deconstruct(out int X, out int Y) { X = this.X; Y = this.Y; }
- 일반 구조체에서는 해당 메서드가 자동으로 생성되지 않기에 수동으로 구현해야 한다.
- 위치 레코드 구조체의 장점으로는
자동 생성된 멤버
,불변성 지원
,코드 간결성
이 있다.
record class
의 각 기본 생성자 매개 변수에 대한 공개 초기화
전용 속성을 합성한다.레코드 클래스에서 기본 생성자를 정의하면, 컴파일러는 각 매개 변수에 대응하는 공개 init 전용 속성
을 자동으로 생성한다.
읽기 전용
이며 객체 init
또는 with
식을 통해서만 값을 설정할 수 있다.
public record class Person(string FirstName, string LastName);
public string FirstName { get; init; }
public string LastName { get; init; }
record struct
에서 컴파일러는 공개 읽기/쓰기 속성을 합성한다.기본 생성자(위치 매개 변수)를 정의하면, 컴파일러는 각 매개 변수에 대응하는 공개 읽기/쓰기 속성을 자동으로 생성한다.
public record struct Point(int X, int Y);
public int X { get; set; }
public int Y { get; set; }
record
한정자를 포함하지 않는 class
및 struct
형식에서 기본 생성자 매개 변수에 대한 속성을 만들지 않는다.기본 생성자(위치 매개 변수)
를 사용할 수 없다.기본 생성자 매개 변수에 대한 속성을 생성 않는다.