struct
키워드를 사용해 구조체를 선언할 수 있다.
C의 구조체와 다르게 필드뿐 아니라 메소드도 가질 수 있다.
이 때, 구조체 또한 object클래스를 상속하기 때문에 object의 메소드를 오버라이드할 수 있다.
namespace Program
{
struct Gorani
{
public int age;
public int id;
public Gorani(int age, int id)
{
this.age = age;
this.id = id;
}
public override string ToString()
{
return $"Gorani ID:{id} -- AGE:{age}";
}
}
class Program
{
public static void Main(string[] args)
{
Gorani a; // new 없이 선언
a.id = 1;
a.age = 10;
Gorani b = new Gorani(456, 2); // new로 선언
Gorani c = b; // 값형식이므로 깊은복사
c.id = 3;
c.age = 789;
Gorani[] goranis = { a, b, c };
foreach( Gorani gorani in goranis)
{
Console.WriteLine(gorani);
}
}
}
}
struct
앞에 readonly
키워드를 붙여 변경 불가능 구조체로 선언할 수 있다.
이 경우 모든 필드도 readonly
로 선언되어야 한다.
(생성자에서만 필드 초기화 가능)
namespace Program
{
readonly struct Gorani
{
public readonly int id;
public Gorani(int id)
{
this.id = id;
}
public override string ToString()
{
return $"Gorani ID:{id}";
}
}
class Program
{
public static void Main(string[] args)
{
Gorani a = new Gorani(1); // 생성자 호출 --> 정상컴파일
Gorani b; // new 없이 선언
b.id = 2; // --> 컴파일에러 (생성자 밖에서 필드 수정시도)
}
}
}
구조체 내의 메소드에 readonly
키워드를 붙여 읽기 전용 메소드로 선언할 수 있다.
이 메소드 내에서는 필드 값을 변경할 수 없다.
namespace Program
{
struct Gorani
{
public readonly int id;
public int canbeChanged;
public Gorani(int id, int canbeChanged)
{
this.id = id;
this.canbeChanged = canbeChanged;
}
public readonly void IamMethod()
{
canbeChanged += 1; // 컴파일에러
// (readonly 메소드에서 필드값을 바꾸려고해서)
}
}
class Program
{
public static void Main(string[] args)
{
Gorani a = new Gorani(1, 555);
}
}
}
필드를 담을 수 있는 형식 이름이 없는 구조체
가장 앞 요소부터 Item1, Item2, Item3, ..., ItemN 으로 자동 명명된다.
public static void Main(string[] args)
{
var a = (123, true, "aa");
Console.WriteLine(a); // (123, True, aa)
Console.WriteLine($"{a.Item1} {a.Item2} {a.Item3}"); // 123 True aa
}
이름있는 필드를 담을 수 있는 튜플
식별자 : 값
public static void Main(string[] args)
{
// 이름있는 튜플
var a = (x: 123, y: "abc");
Console.WriteLine(a); // (123, abc)
Console.WriteLine($"x : {a.x}, y : {a.y}"); // x : 123, y : abc
}
튜플 분해를 통해 변수를 생성하고 초기화 할 수 있다.
_
로 특정 필드를 무시할 수 있다. 만약 _
에 접근하려고 하면 "컨텍스트에 없다"는 컴파일 오류를 뱉는다.
가장 마지막 부분의 switch식으로 표현된 코드는 튜플의 위치 패턴 매칭
이라고 불린다.
public static void Main(string[] args)
{
var a = (x: false, y: 5.3);
// 변수 생성+초기화
var (xx, yy) = a;
yy = 53.53;
Console.WriteLine($"xx : {xx}, yy : {yy}"); // xx : False, yy : 53.53
// _ 로 특정필드 무시 ( _는 없는 식별자)
var (_, yyy) = a;
Console.WriteLine($"x값 없다, yyy : {yyy}"); // x값 없다, yyy : 5.3
// 위치패턴 매칭 (분해의 활용 예)
var result = a switch
{
(bool b, double d) when b == true => "true다",
(false, double d) when d > 5.0 => "false고 5.0보다 크다",
(false, _) => "false고 5.0 이하다",
_ => "디폴트다",
};
Console.WriteLine(result); // false고 5.0보다 크다
}
필드의 갯수, 형식이 같은 튜플은 서로 대입할 수 있다.
public static void Main(string[] args)
{
var a = ( x: false, y: 5.3 );
var b = ( true, 9999.999 );
Console.WriteLine(a); // (False, 5.3)
Console.WriteLine(b); // (True, 9999.999)
Console.WriteLine();
a = b;
Console.WriteLine(a); // (True, 9999.999)
Console.WriteLine();
b = (xx: false, yy: 123.123); // xx, yy는 사실 쓸모가 없다.
Console.WriteLine(b); // (False, 123.123)
Console.WriteLine();
}