get
접근자: 내부 필드 값을 읽고 외부로 출력할 때set
접근자: 내부 필드에 새로운 값을 할당/입력할 때class MyClass
{
private int myField;
public int MyField
{
get
{
return myField;
}
set
{
myField = value;
}
}
}
=
할당 연산자를 통해 private 변수
의 데이터를 저장 및 읽어오기가 가능하다.get
접근자만 구현할 경우 읽기 전용이 된다.예제 프로그램
using System;
namespace Property
{
class BirthdayInfo
{
private string name;
private DateTime birthday;
public string Name // 읽기&쓰기
{
get
{
return name;
}
set
{
name = value;
}
}
public DateTime Birthday // 읽기&쓰기
{
get
{
return birthday;
}
set
{
birthday = value;
}
}
public int Age // 읽기 전용
{
get
{
return new DateTime(DateTime.Now.Subtract(birthday).Ticks).Year;
}
}
}
class MainApp
{
static void Main(string[] args)
{
BirthdayInfo birth = new BirthdayInfo();
// set : 쓰기
birth.Name = "서현";
birth.Birthday = new DateTime(1991, 6, 28);
// get : 읽기
Console.WriteLine("Name : {0}", birth.Name);
Console.WriteLine("Birthday : {0}", birth.Birthday.ToShortDateString());
Console.WriteLine("Age : {0}", birth.Age);
}
}
}
아래와 같이 필드를 단순히 읽고 쓰기만 하는 프로퍼티는 코드를 더 단순하게 만드는 자동 구현 프로퍼티를 사용할 수 있다. (C#3.0부터 도입)
필드 선언 필요X
get접근자, set접근자 뒤에 세미콜론(;
) 붙이기
// 원래 코드 //
public class NameCard
{
private string name;
private string phoneNumber;
public string Name
{
get { return name; }
set { name = value; }
}
public string PhoneNumber
{
get { return phoneNumber; }
set { phoneNumber = value; }
}
}
// 자동 구현 프로퍼티 //
public class NameCard
{
// 1. 필드 생략
public string Name
{
get; set; // 2. get, set 선언 후 세미콜론
}
public string PhoneNumber
{
get; set;
}
}
C#7.0부터는 자동 구현 프로퍼티 선언과 동시에 초기화를 수행할 수 있다.
public class NameCard
{
public string Name{ get; set;} = "Unknown";
public string PhoneNumber{ get; set; } = "000-0000";
}
예제 프로그램
using System;
namespace AutoImplementedProperty
{
class BirthdayInfo
{
// 선언 & 초기화
public string Name { get; set;} = "Unknown";
public DateTime Birthday{ get; set; } = new DateTime(1, 1, 1);
// 읽기 전용
public int Age
{
get
{
return new DateTime(DateTime.Now.Subtract(Birthday).Ticks).Year;
}
}
}
class MainApp
{
static void Main(string[] args)
{
// 읽기
BirthdayInfo birth = new BirthdayInfo();
Console.WriteLine($"Name : {birth.Name}");
Console.WriteLine($"Birthday : {birth.Birthday.ToShortDateString()}");
Console.WriteLine($"Age : {birth.Age}");
// 쓰기
birth.Name = "서현";
birth.Birthday = new DateTime(1991, 6, 28);
// 읽기
Console.WriteLine($"Name : {birth.Name}");
Console.WriteLine($"Birthday : {birth.Birthday.ToShortDateString()}");
Console.WriteLine($"Age : {birth.Age}");
}
}
}
클래스이름 인스턴스 = new 클래스이름()
{
프로퍼티1 = 값,
프로퍼티2 = 값,
프로퍼티3 = 값
};
예제 프로그램
using System;
namespace ConstructorWithProperty
{
class BirthdayInfo
{
public string Name
{
get;
set;
}
public DateTime Birthday
{
get;
set;
}
public int Age
{
get
{
return new DateTime(DateTime.Now.Subtract(Birthday).Ticks).Year;
}
}
}
class MainApp
{
static void Main(string[] args)
{
// 객체 생성시 프로퍼티 이용해 필드 초기화
BirthdayInfo birth = new BirthdayInfo()
{
Name = "서현",
Birthday = new DateTime(1991, 6, 28)
};
Console.WriteLine("Name : {0}", birth.Name);
Console.WriteLine("Birthday : {0}", birth.Birthday.ToShortDateString());
Console.WriteLine("Age : {0}", birth.Age);
}
}
}
init
접근자를 통해 객체 초기화를 할 때만 외부에서 프로퍼티 변경이 가능하도록 개선되었다.set
접근자 대신 init
접근자를 명시하면 됨public class Transaction
{
public string From {get; init;}
public string To {get; init;}
public int Amount {get; init;}
}
예제 프로그램
using System;
namespace System.Runtime.CompilerServices
{
public class IsExternalInit{}
}
namespace InitOnly
{
class Transaction
{
// set대신 init 선언
public string From { get; init; }
public string To { get; init; }
public int Amount { get; init; }
public override string ToString()
{
return $"{From,-10} -> {To,-10} : ${Amount}";
}
}
class MainApp
{
static void Main(string[] args)
{
Transaction tr1 = new Transaction{From="Alice", To="Bob", Amount=100};
Transaction tr2 = new Transaction{From="Bob", To="Charlie", Amount=50};
Transaction tr3 = new Transaction{From="Charlie", To="Alice", Amount=50};
// tr1.Amount = 30; → 실행할 경우 컴파일 에러 발생 (init 접근자는 초기화 이후 발생하는 프로퍼티 수정을 허용하지 않으므로)
Console.WriteLine(tr1);
Console.WriteLine(tr2);
Console.WriteLine(tr3);
}
}
}
record
키워드 init
)레코드에는 초기화 전용 자동 구현 프로퍼티뿐만 아니라
쓰기 가능한 프로퍼티와 필드도 자유롭게 선언할 수 있다.
record RTransaction
{
public string From { get; init; }
public string To { get; init; }
public int Amount { get; init; }
}
예제 프로그램
using System;
namespace Record
{
// 레코드 선언
record RTransaction
{
public string From { get; init; }
public string To { get; init; }
public int Amount { get; init; }
public override string ToString()
{
return $"{From,-10} -> {To,-10} : ${Amount}";
}
}
class MainApp
{
static void Main(string[] args)
{
RTransaction tr1 = new RTransaction
{
From="Alice", To="Bob", Amount=100
};
RTransaction tr2 = new RTransaction
{
From="Alice", To="Charlie", Amount=100
};
Console.WriteLine(tr1);
Console.WriteLine(tr2);
}
}
}
예제 프로그램
using System;
namespace System.Runtime.CompilerServices
{
public class IsExternalInit{}
}
namespace WithExp
{
record RTransaction
{
public string From { get; init; }
public string To { get; init; }
public int Amount { get; init; }
public override string ToString()
{
return $"{From,-10} -> {To,-10} : ${Amount}";
}
}
class MainApp
{
static void Main(string[] args)
{
RTransaction tr1 = new RTransaction{From="Alice", To="Bob", Amount=100};
// tr1 복사 - To 프로퍼티 값만 "Charlie"로 수정
RTransaction tr2 = tr1 with {To="Charlie"};
// tr2 복사 - From, Amount 프로퍼티 각각 "Dave", 30으로 수정
RTransaction tr3 = tr2 with {From="Dave", Amount=30};
Console.WriteLine(tr1);
Console.WriteLine(tr2);
Console.WriteLine(tr3);
}
}
}
Equals()
메소드를 자동으로 구현해 Equals()
메소드를 구현하지 않아도 비교가 가능하다.예제 프로그램
using System;
namespace RecordComp
{
class CTransaction // 클래스 - Equals() 구현 생략
{
public string From { get; init; }
public string To { get; init; }
public int Amount { get; init; }
public override string ToString()
{
return $"{From,-10} -> {To,-10} : ${Amount}";
}
}
record RTransaction // 레코드
{
public string From { get; init; }
public string To { get; init; }
public int Amount { get; init; }
public override string ToString()
{
return $"{From,-10} -> {To,-10} : ${Amount}";
}
}
class MainApp
{
static void Main(string[] args)
{
CTransaction trA = new CTransaction { From = "Alice", To = "Bob", Amount = 100 };
CTransaction trB = new CTransaction { From = "Alice", To = "Bob", Amount = 100 };
Console.WriteLine(trA);
Console.WriteLine(trB);
Console.WriteLine($"trA equals to trB : {trA.Equals(trB)}");
// Equals() 기본 구현은 내용 비교가 아닌 참조를 비교하므로 False 출력
RTransaction tr1 = new RTransaction { From = "Alice", To = "Bob", Amount = 100 };
RTransaction tr2 = new RTransaction { From = "Alice", To = "Bob", Amount = 100 };
Console.WriteLine(tr1);
Console.WriteLine(tr2);
Console.WriteLine($"tr1 equals to tr2 : {tr1.Equals(tr2)}");
}
}
}
/* 중괄호 사이에 임의의 프로퍼티 이름을 적고 값을 할당하면
그대로 새 형식의 프로퍼티가 된다. */
var myInstance = new {Name="박상현", Age="17"};
// 프로퍼티 사용
Console.WriteLine(myInstance.Name, myInstance.Age);
예제 프로그램
using System;
namespace AnonymousType
{
class MainApp
{
static void Main(string[] args)
{
// 무명형식 : 선언과 동시에 인스턴스 할당
var a = new { Name="박상현", Age=123 };
Console.WriteLine("Name:{0}, Age:{1}", a.Name, a.Age);
var b = new { Subject = "수학", Scores = new int[] { 90, 80, 70, 60 } };
Console.Write("Subject:{0}, Scores: ", b.Subject);
foreach(var score in b.Scores )
Console.Write("{0} ", score );
Console.WriteLine();
}
}
}
interface 인터페이스이름
{
public 형식 프로퍼티이름1
{
get; set;
}
public 형식 프로퍼티이름2
{
get; set;
}
// ...
}
예제 프로그램
using System;
namespace PropertiesInInterface
{
interface INamedValue // 인터페이스는 어떤 구현도 가지지 않는다.
{
string Name
{
get;
set;
}
string Value
{
get;
set;
}
}
class NamedValue : INamedValue // 파생 클래스 - 반드시 Name과 Value 구현해야함(자동구현프로퍼티 이용 가능)
{
public string Name
{
get;
set;
}
public string Value
{
get;
set;
}
}
class MainApp
{
static void Main(string[] args)
{
NamedValue name = new NamedValue()
{ Name = "이름", Value = "박상현" };
NamedValue height = new NamedValue()
{ Name = "키", Value = "177Cm" };
NamedValue weight = new NamedValue()
{ Name = "몸무게", Value = "90Kg" };
Console.WriteLine("{0} : {1}", name.Name, name.Value);
Console.WriteLine("{0} : {1}", height.Name, height.Value);
Console.WriteLine("{0} : {1}", weight.Name, weight.Value);
}
}
}
abstract
한정자 사용 abstract class 추상 클래스이름
{
abstract 데이터형식 프로퍼티이름
{
get;
set;
}
}
예제 프로그램
using System;
namespace PropertiesInAbstractClass
{
// 추상 클래스
abstract class Product
{
private static int serial = 0;
public string SerialID // 추상클래스는 구현을 가진 프로퍼티와
{
get { return String.Format("{0:d5}", serial++); }
}
abstract public DateTime ProductDate // 구현이 없는 추상 프로퍼티 모두를 가질 수 있다.
{
get;
set;
}
}
// 파생 클래스
class MyProduct : Product
{
// 파생 클래스는 기반 추상 클래스의 모든 추상 메소드뿐 아니라 추상 프로퍼티를 재정의해야 한다.
public override DateTime ProductDate
{
get;
set;
}
}
class MainApp
{
static void Main(string[] args)
{
Product product_1 = new MyProduct()
{ ProductDate = new DateTime(2010, 1, 10) };
Console.WriteLine("Product:{0}, Product Date :{1}",
product_1.SerialID,
product_1.ProductDate);
Product product_2 = new MyProduct()
{ ProductDate = new DateTime(2010, 2, 3) };
Console.WriteLine("Product:{0}, Product Date :{1}",
product_2.SerialID,
product_2.ProductDate);
}
}
}
using System;
namespace Ex9_1
{
class NameCard
{
private int age;
private string name;
public int GetAge()
{ return age; }
public void SetAge(int value)
{ age = value; }
public string GetName()
{ return name; }
public void SetName(string value)
{ name = value; }
}
class MainApp
{
public static void Main()
{
NameCard MyCard = new NameCard();
MyCard.SetAge(24);
MyCard.SetName("상현");
Console.WriteLine("나이 : {0}", MyCard.GetAge());
Console.WriteLine("이름 : {0}", MyCard.GetName());
}
}
}
// 변경 후 코드
using System;
namespace Ex9_1
{
class NameCard
{
public int Age
{
get;
set;
}
public string Name
{
get;
set;
}
}
class MainApp
{
static void Main()
{
NameCard Mycard = new NameCard();
Mycard.Age = 24;
Mycard.Name = "상현";
Console.WriteLine($"나이 : {Mycard.Age}");
Console.WriteLine($"이름 : {Mycard.Name}");
}
}
}
이름:박상현, 나이:17
Real:3, Imaginary:-12
using System;
namespace Ex9_2
{
class MainApp
{
static void Main(string[] args)
{
var nameCard = new { Name="박상현", Age=17};
Console.WriteLine("이름:{0}, 나이:{1}", nameCard.Name, nameCard.Age);
var complex = new { Real=3, Imaginary=-12};
Console.WriteLine("Real:{0}, Imaginary:{1}",
complex.Real, complex.Imaginary);
}
}
}