-
C# 클래스 간의 형변환, 중첩 클래스, 델리 게이트, 콜백 메서드(교육 14일차)C# 2020. 6. 4. 12:50
클래스 간의 형 변환
타입을 정의하는 것은 "단위(unit)"을 빈번하게 사용하는 프로그램에서도 유용하다. 통화 단위를 생각할 때 원화 달러 엔화가 있을 때 이를 단순히 decimal하나로 지정한다면 자칫 중요한 금전 계산에 오류가 발생할 여지가 남는다.
decimal dollar = 10; //10 달러 decimal won = dollar * 1200; //12,000 원 decimal yen = won/10 //1200엔 yen = dollar; 프로그램 오동작의 원인
Currency는 프로퍼티로 money 변수를 초기화하고 반환하는 부모 클래스로부터 상속받은 Won, Dollar, Yen 클래스를 만든다.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _20200604_0001 { public class Currency { decimal money; public decimal Money { get { return money; } } public Currency(decimal money) { this.money = money; } } public class Won : Currency { public Won(decimal money) : base(money) { } public override string ToString() { return Money + " Won"; } } public class Dollar : Currency { public Dollar(decimal money) : base(money) { } public override string ToString() { return Money + " Dollar"; } } public class Yen : Currency { public Yen(decimal money) : base(money) { } public override string ToString() { return Money + " Yen"; } } class Program { static void Main(string[] args) { Won awon = new Won(1000); Dollar adollar = new Dollar(1); Yen ayen = new Yen(13); Console.WriteLine(awon); } } }
각 자식 클래스들의 생성자는 부모 클래스의 변수를 상속받아서 각 money를 초기화하고 ToString 메서드를 오버라이드 해서 출력한다. 그렇다면 Won의 객체와 Yen의 객체가 있을 때 Won을 Yen으로 환율에 맞춰 변환하고 싶을 때 쓰는 방법이 암시적(implicit) 형 변환, 명시적(explicit) 형 변환이다.
public class Won : Currency { public Won(decimal money) : base(money) { } public override string ToString() { return Money + " Won"; } static public implicit operator Won(Yen yen) //엔화를 원화로 변환 { return new Won(yen.Money * 13m); //1엔당 13원으로 가정 } } static void Main(string[] args) { Won awon = new Won(1000); Dollar adollar = new Dollar(1); Yen ayen = new Yen(13); awon = ayen; //암시적 형변환 Console.WriteLine(awon); }
static public implicit operator Won(Yen yen) 메서드를 통해 엔 객체를 매개변수로 입력받아 새로운 객체를 리턴한다.
자료형을 형 변환할 때 마치 암시적 형 변환을 하는 것 같은 형태를 띤다.
public class Won : Currency { public Won(decimal money) : base(money) { } public override string ToString() { return Money + " Won"; } static public explicit operator Won(Yen yen) //엔화를 원화로 변환 { return new Won(yen.Money * 13m); //1엔당 13원으로 가정 } } static void Main(string[] args) { Won awon = new Won(1000); Dollar adollar = new Dollar(1); Yen ayen = new Yen(13); awon = (Won)ayen; //캐스팅 명시적 형변환 Console.WriteLine(awon); }
implicit으로 바꿔주면 암시적 형 변환이 안되도록 하며, 프로그래머가 명시해야 형변환이 일어나도록 해준다.
추상 클래스
건물의 설계도면이 있을 때, 그대로 따라하면 지을 수 있다. 설계 가이드를 통해 설계 도면을 만들고 도면을 통해 객체를 만들 수 있다. 설계 도면은 class이고 설계 가이드는 추상 클래스이다. 설계 가이드에는 예를 들어 창문이 몇개 있어야 한다거나, 화장실 몇개 있어야 하는지 등등이 명시되어 있을 것이다. 도면은 구체적이어야 하고 이 구체적인 것을 실체화 한 것이 객체이다. 두리둥실하게 만들어 놓은 것이 추상 클래스이다. 가이드 역할을 한다. 설계 도면을 만드는 건 구체적으로 짜야하고 추상 클래스는 가이드라인을 제공한다.
abstract class DrawingObject //추상 클래스 { public abstract void Draw(); //추상 메서드(코드 없는 가상 메서드) public void Move() {Console.WriteLine("Move"); //일반 메서드도 정의 가능 }
추상 클래스를 상속받으면 반드시 추상 클래스를 구현해야 한다. 그렇지 않으면 상속 받은 자식 클래스도 추상 클래스가 된다.
델리게이트
메서드의 주소도 가지는 애를 담는 것을 델리게이트라고 한다. 메소드 참조변수. 사용 방법은 abstract와 유사하다.
class 타입이름
{
내용정의
}
delegate(새로운 자료형 생성) 반환형 타입이름 ( 인자 )
객체 생성
Car obj = new Car();
Calcdelegate obj = new Calcdelegete();
obj= 메소드이름 //대입가능
class Program { delegate void CarDeal(); static void Car() { Console.WriteLine("메뚜기"); } static void Main(string[] args) { Car(); CarDeal Dealer; Dealer = Car; Dealer(); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _20200604_003 { class Program { delegate void CarDeal(); delegate void CarDeal2(int z); static void Car() { Console.WriteLine("메뚜기"); } static void Car2(int A) { Console.WriteLine("메뚜기2 " + A); } static void Ottogi() { Console.WriteLine("오뚜기"); } static void Main(string[] args) { Car(); CarDeal Dealer; Dealer = Car; Dealer(); Dealer = Ottogi; Dealer(); CarDeal2 Dealer2; Dealer2 = Car2; Dealer2(100); } } }
Program 클래스 안에서 매개변수가 없는 델리게이트와 int형 매개번수 하나가 있는 델리게이트를 정의한다, 가장 처음에 Car()메소드를 호출한다. 다음으로 델리게이트 CarDeal을 자료형으로 가지는 Dealer를 하나 만든다. 델리게이트는 메소드를 가리킬 수 있으므로 Car() 메소드를 Dealer에 대입한다. 따라서 Dealer()를 호출할 경우 Car()가 호출된다. 오뚜기도 마찬가지이다. 다음으로 매개변수를 하나 가지는 델리게이트에 대해서는 똑같이 매개변수를 하나 가지는 메서드를 대입해서 매개변수를 주고 값을 출력했다.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _20200604_003 { public class Mathematics { delegate int CalcDelegate(int x, int y); static int Add(int x, int y) { return x + y; } static int Subtract(int x, int y) { return x - y; } static int Multiply(int x, int y) { return x * y; } static int Divide(int x, int y) { return x / y; } CalcDelegate[] methods; public Mathematics() { methods = new CalcDelegate[] { Mathematics.Add, Mathematics.Subtract, Mathematics.Multiply, Mathematics.Divide }; } public void Calculate(char opCode, int operand1, int operand2) { switch (opCode) { case '+': Console.WriteLine("+: " + methods[0](operand1, operand2)); break; case '-': Console.WriteLine("-: " + methods[1](operand1, operand2)); break; case '*': Console.WriteLine("*: " + methods[2](operand1, operand2)); break; case '/': Console.WriteLine("/: " + methods[3](operand1, operand2)); break; } } } class Program { //3개의 매개변수를 받고 void 를 반환하는 델리게이트 정의 // 매개변수의 타입이 중요할 뿐 매개변수의 이름은 임의로 정할 수 있음 delegate void WorkDelegate(char arg1, int arg2, int arg3); static void Main(string[] args) { Mathematics math = new Mathematics(); WorkDelegate work = math.Calculate; work('+', 10, 5); work('-', 10, 5); work('*', 10, 5); work('/', 10, 5); } } }
Mathematics 클래스 내부에서는 델리게이트 매개변수 int형 2개를 가지고 있는 CalcDelegate를 만들어 Add, Subtract, Multiply, Divide 4개의 메소드를 CalcDelegate의 타입을 가진 method라는 배열을 만들어서 0,1,2,3 인덱스에 각각 메서드를 넣는다. 다음 부분은 연산자에 따라 연산종류를 결정하고 계산결과를 출력하는 메서드이다. 매개변수가 3개가 사용되는데, 메인 메서드 윗 부분에서 델리게이트 변수를 만들 때도 같은 타입과 갯수로 생성하는 것을 볼 수 있다. 메인메서드 부분에서는 Mathematics 클래스를 자료형으로 가진 객체 math를 만들고 그 밑의 줄은 델리게이트 work 에 위에서 만든 연산자에 따른 종류를 판별하고 계산 메서드를 호출하는 메서드를 저장한다.
하나의 델리게이트에 여러개의 메서드를 추가할 수 있는 방법
using System; using System.CodeDom; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _20200604_004 { class Program { delegate void CalcDelegate(int x, int y); static void Add(int x, int y) { Console.WriteLine(x + y); } static void Subtract(int x, int y) { Console.WriteLine(x - y); } static void Multiply(int x, int y) { Console.WriteLine(x * y); } static void Divide(int x, int y) { Console.WriteLine(x / y); } static void Main(string[] args) { CalcDelegate calc = Add; calc += Subtract; calc += Multiply; calc += Divide; //메서드를 하나하나 넣어준다 //일종의 배열처럼 순서대로 calc(10, 5); } } }
델리게이트 calc에 다밀어넣고 인자만 넣어주면 알아서 하나하나 실행 시켜준다. 자동화된 foreach문과 비슷한 형태이다. +=연산자는 추가하는 연산자라면 -=는 빼는 명령어이다.
다음 설명을 확인하고 내용을 반영하여 클래스 3개를 코드로 구현하시오.
부모 클래스, 자식 클래스의 구조를 구현하시오.
부모 클래스명은 Person으로 구현하시오.
상속받는 클래스명은 Developer와 Sales로 구현하시오.
부모 클래스의 필드 3가지를 이름(name), 나이(age), 부서(dept)로 하고 타입을 적절하게 선택하여 작성하시오.
부모 클래스의 필드 3가지를 string형으로 리턴하는 ToString메소드를 오버라이드하여 작성하시오.
부모 클래스에서 가상 메소드를 구현하여야 하며 "회사원 입니다."를 화면에 출력하는 기능을 부여하시오.
Developer 클래스는 부모 클래스를 상속받으며 가상 메소드를 재정의해서 "개발자 입니다."라고 화면에 출력하게 하시오.
Sales 클래스는 부모 클래스를 상속받으며 가상 메소드를 재정의해서 "세일즈맨 입니다."라고 화면에 출력하게 하시오.
Main() 메소드가 포함된 Program 클래스를 구현하시오.
Main() 메소드에는 Person 배열을 생성하고 2명의 신상 정보를 Developer, Sales 객체를 생성하며 입력하시오.
Main() 메소드의 Person 배열을 foreach문을 사용하여 객체 정보를 출력하고 가상메소드를 호출하시오.using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _20200604_005 { class Person { protected string name; protected int age; protected string dept; virtual public void Who_are_you() { Console.WriteLine("회사원 입니다."); Console.WriteLine("=============="); } public override string ToString() { return "성명 : " + name + "\n나이 : " + age + "\n부서 : " + dept; } } class Developer : Person { public Developer(string name, int age, string dept) { this.name = name; this.age = age; this.dept = dept; } public override void Who_are_you() { Console.WriteLine("개발자 입니다."); } public override string ToString() { return "성명 : " + name + "\n나이 : " + age + "\n부서 : " + dept; } } class Sales : Person { public Sales(string name, int age, string dept) { this.name = name; this.age = age; this.dept = dept; } public override void Who_are_you() { Console.WriteLine("개발자 입니다."); } public override string ToString() { return "성명 : " + name + "\n나이 : " + age + "\n부서 : " + dept; } } class Program { static void Main(string[] args) { Console.WriteLine("과정명 : 스마트팩토리 과정"); Console.WriteLine("교과목 : C# OOP/자료구조"); Console.WriteLine("응시일 : 2020.06.04."); Console.WriteLine("응시자 : 김효용\n"); Person[] people = new Person[2] { new Developer("홍길동",27,"연구소"), new Sales("고길동",25,"판매")}; foreach(Person index in people) { Console.WriteLine(index); index.Who_are_you(); Console.WriteLine("==============="); } } } }
콜백 메서드
운영체제 쪽에서 나온 개념, 메서드 중에 우리가 호출하는게 있고, 알아서 불러주는 메서드가 있다.
Main 메서드 우리가 호출하는게 아님
어떤 이벤트에 의해 호출 되는 메서드.
명시적으로 호출되는 메서드가 아닌 특정한 상황에 따라서 자동으로 호출되는 메서드
'C#' 카테고리의 다른 글
C# 윈폼 (2020.06.15) (0) 2020.06.15 C# GitHub, 제네릭, 애트리뷰트, 예외, 스레드 (2020.06.15) (0) 2020.06.15 C# 오버라이드, 오버로드 (13일차) (0) 2020.06.03 C# Object Class(조상)+메서드 4종세트, 배열의 조상(System.Array) base, 다형성 (교육 12일차) (0) 2020.06.02 C# 캡슐화, 정보 은닉, 상속, 클래스 형변환 (교육 11일차) 메모리 주소확인 (0) 2020.06.01