[ 학습 흐름 ]
[ 학습 흐름]
- 분기문
- if , else 그리고 else if
- if 문 중첩해서 사용하기
- switch
- 반복문
- while
- do while
- for
- 중첩 for
- foreach
- for 또는 while을 이용한 무한 반복 코드
- 점프문
- continue
- goto
- return 과 throw
[ 분기문 ]
[ 분기문 ]
- 프로그램의 흐름을 조건에 따라 여러 갈래로 나누는 흐름 제어 구문 .
- if문 switch문 두 종류가 있다 .
[ if , else , else if ]
- 한번에 단 하나의 조건을 평가한다 .
using System;
namespace AssignmentOperator;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
Console.WriteLine("숫자를 입력하세요");
//사용자로부터 문자열을 입력받아 그 결과를 반환
string input = Console.ReadLine();
int number=Int32.Parse(input);
if (number < 0)
Console.WriteLine("음수");
else if (number > 0)
Console.WriteLine("양수");
else
Console.WriteLine("0");
if (number % 2 == 0)
Console.WriteLine("짝수");
else
Console.WriteLine("홀수");
}
}
[ if 문 중첩해서 사용하기 ]
- 분기문,반복문 등의 흐름 제어문은 또 다른 흐름 제어문과 중첩하여 사용 가능하다 .
- 프로그램의 흐름은 가급적 단순하고 명료하게 유지하는것이 좋다 .
using System;
namespace AssignmentOperator;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
Console.WriteLine("숫자를 입력하세요");
//사용자로부터 문자열을 입력받아 그 결과를 반환
string input = Console.ReadLine();
int number=Int32.Parse(input);
if (number > 0)
{
if (number % 2 == 0)
Console.WriteLine("0보다 큰 짝수");
else
Console.WriteLine("0보다 큰 홀수");
}
else
Console.WriteLine("0보다 작거나 같은 수");
}
}
[ switch 문 ]
Switch 문
- 조건식의 결과가 가질 다양한 경우를 한번에 평가하고 프로그램의 흐름을 가른다 .
- 사용되는 break 문 대신에 goto / return / throw와 같은 점프문 사용이 문법적으로 가능하다 .
switch (조건식)
{
//switch 절
case 패턴 1: //switch 레이블
//실행 코드
break; //브레이크문
}
using System;
namespace Switch;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
Console.WriteLine("요일을 입력해주세요");
string day = Console.ReadLine();
switch(day)
{
case "일":
Console.WriteLine("Sunday");
break;
case "월":
Console.WriteLine("Monday");
break;
case "화":
Console.WriteLine("Tuesday");
break;
case "수":
Console.WriteLine("Wednesday");
break;
case "목":
Console.WriteLine("Thursday");
break;
case "금":
Console.WriteLine("Friday");
break;
case "토":
Console.WriteLine("Saturday");
break;
default:
Console.WriteLine("없는 요일");
break;
}
}
}
Switch 문과 패턴 매칭
- switch 레이블의 패턴에는 상수와 형식을 비롯 관계,논리등 C#이 지원하는 다양한 패턴 적용이 가능하다 .
- Parse 메서드는변환 실패시 예외를 던지는데 , 이때 프로그램은 현재 코드의 실행을 멈추고 흐름을 다른곳으로 이동한다.
-TryParse메서드는 변환의 성공 여부를 반환하기에 현재 코드의 흐름을 유지 할 수 있다 .
- TryParse가 변환한 데이터는 두번째 매개변수에 저장된다 .
//C# 컴파일러는 123 리터럴을 평가해 int형식임을 유추한다 . 이후 obj안에 박싱해넣는다 .
object obj =123 ;
switch(obj)
{
//obj에 담겨 있는 데이터 형식이 int 이므로 프로그램은 이 case 절을 따라가 분기함
case int:
//실행
break;
}
using System;
namespace Switch;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
object obj = null;
string s = Console.ReadLine();
if (int.TryParse(s, out int out_i))
obj = out_i;
else if (float.TryParse(s, out float out_f))
obj = out_f;
else
obj = s;
switch(obj)
{
case int:
Console.WriteLine($"{(int)obj}는 int형식입니다");
break;
case float:
Console.WriteLine($"{(float)obj}는 float형식입니다");
break;
default:
Console.WriteLine($"{obj}는 모르는 형식입니다");
break;
}
}
}
케이스 가드
- switch 문의 case 절의 패턴을 더 구체적으로 만들어주는 추가적인 조건 검사
- case 절 뒤에 when 절을 붙여 사용한다 .
case float f when f>=0 :
Console.WriteLine($"{f}는 양의 float 형식입니다");
break;
case float:
Console.WriteLine($"{f}는 음의 float 형식입니다");
break;
[ switch 식 ]
-분기를 거쳐 값을 내야 하는 경우에는 switch식을 사용한다 .
//모든 case 절과 default절 에서 하는 일은 grade 에 등급별 학점을 저장하는 것이다 .
switch(score)
{
case 90:
grade = "A";
break;
case 80:
grade = "B";
break;
}
- 위와 같은 경우는 switch 식을 사용하면 간단하게 바꿀 수 있다 .
string grade = score switch
{
90 when repeated ==true =>"B+",
90 => "A",
80 => "B",
_ => "F"
};
- 케이스 가드를 이용한 추가 분기 처리도 가능하다 .
using System;
namespace SwitchExp;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
Console.WriteLine("점수를 입력하세요 .");
int score = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("재수강인가요? (y/n)");
string line = Console.ReadLine();
bool repeated = (line == "y") ? true : false;
string grade = (int)(Math.Truncate(score / 10.0) * 10) switch
{
90 when repeated==true=>"B+",
90=>"A",
80=>"B",
70=>"C",
60=>"D",
50=>"E",
_ => "F"
};
Console.WriteLine($"학점 : {grade}");
}
}
[ 반복문 ]
[ 반복문 ]
- 특정 조건을 만족하는 동안 코드/코드블록을 반복해서 실행하도록 하는 문장 .
- while / do while / for / foreach 문 네 종류가 있다 .
[ while ]
- 조건식을 평가후 그 결과가 참이라면 코드를 반복 실행한다 .
while (조건식)
반복 실행할 코드
using System;
namespace While;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
int i = 10;
while(i>0)
{
Console.WriteLine($"i : {i--}");
}
}
}
[ do while ]
- 조건식을 평가하기 전 무조건 한 번은 코드를 실행후 평가하여 반복실행 .
do
{
//반복실행할 코드 블록
}while(조건식);
using System;
namespace While;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
int i = 10;
do
{
Console.WriteLine("a) i : {0}", i--);
} while (i > 0);
do
{
Console.WriteLine("b) i : {0}", i--);
}
while (i > 0);
}
}
[ for ]
- while문 보다 더 정교한 반복제어
for(초기화식;조건식;반복식)
반복 실행할 코드
- 초기화식 : 반복을 실행하기 전에 가장 먼저 딱 한번 실행되는 코드 . for 반복문에서 사용할 변수등을 이곳에서 초기화.
- 조건식 : 반복을 계속 수행할지 결정하는 식
- 반복식 : 반복이 끝날때마다 실행 . 주로 조건식에서 사용하는 변수의 값 조정 . 반복식이 실행된 이후 조건식이 실행되어 반복 여부를 결정한다 .
using System;
namespace For;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
for(int i=0;i<5;i++)
{
Console.WriteLine(i);
}
}
}
[ 중첩 for ]
- for문은 while/do while문 보다 반복 제어를 위한 장치가 잘 갖춰져 있기에 반복문을 겹쳐야 한다면 좋은 후보이다 .
using System;
namespace For;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
for(int i=0;i<5;i++)
{
for(int j=0;j<=i;j++)
{
Console.Write("*");
}
Console.WriteLine();
}
}
}
[ foreach ]
- foreach 문은 배열(혹은 컬렉션)을 순회하며 각 데이터 요소에 차례대로 접근하도록 해준다 .
- 배열의 끝에 도달하면 자동으로 반복은 종료된다 .
foreach(데이터 형식 변수명 in 배열 또는 컬렉션)
코드 혹은 코드블록
using System;
namespace ForEach;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
int[] arr = new int[] { 0, 1, 2, 3, 4 };
foreach (int i in arr)
{
Console.WriteLine(i);
}
}
}
[ for 또는 while을 이용한 무한 반복 코드 ]
for(;;)
//반복 실행할 코드블록
- for문의 매개변수에 아무것도 넣지 않으면 무한 실행
using System;
namespace InfinitieFor;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
int i = 0;
for(; ; )
{
Console.WriteLine(i++);
}
}
}
while(true)
//반복 실행할 코드 블록
- 평가 결과가 항상 true로 되도록 만들면 무한 실행 .
using System;
namespace InfinitieWhile;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
int i = 0;
while (true)
Console.WriteLine(i++);
}
}
- 프로그램의 종료는 Ctrl + C / 작업 관리자에서 프로세스 종료 두가지 방법이 있다 .
[ 점프문 ]
[ 점프문 ]
- 흐름을 끊고 프로그램의 실행 위치를 원하는 곳으로 단숨에 도약시킬수 있다 .
- break / continue / goto / return / throw 5가지 종류가 있다 .
[ break ]
- 현재 실행 중인 반복문이나 switch문의 실행을 중단하고자 할 때 사용한다 .
using System;
namespace Break;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
while(true)
{
Console.WriteLine("계속할까요?(예/아니오)");
string answer = Console.ReadLine();
if (answer == "아니오")
break;
}
}
}
[ continue ]
- 반복문을 멈추게 하난 break와 달리 한 회 건너뛰어 반복을 계속 수행하게 한다 .
- 분기문을 통해 같은 효과를 낼 수 있지만 , continue 문이 사용된 코드의 가독성이 더 좋다 .
using System;
namespace Continue;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
for(int i=0;i<10;i++)
{
if (i % 2 == 0)
continue;
Console.WriteLine($"{i} : 홀수");
}
}
}
[ goto ]
goto 레이블;
레이블 :
- 레이블은 코드안의 위치를 나타내는 표지판과 같다 .
- goto문은 레이블이 가리키는 곳으로 바로 뛰어 넘어간다 .
- goto문은 흐름을 끊어 가독성을 줄이므로 선호되지는 않지만 , "중첩된 반복문을 뚫기" 등 특정 상황에서는 유용하다 .
using System;
namespace GoTo;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
Console.WriteLine("종료 조건(숫자)를 입력하세요");
string input = Console.ReadLine();
int input_number = Convert.ToInt32(input);
int exit_number = 0;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
for(int k=0;k<3;k++)
{
if (exit_number++ == input_number)
goto EXIT_FOR;
Console.WriteLine($"ExitNumber : {exit_number}");
}
}
}
goto EXIT_PROGRAM;
EXIT_FOR:
Console.WriteLine("\nExit nested for ...");
EXIT_PROGRAM:
Console.WriteLine("Exit Program ...");
}
}
[ 패턴 매칭 ]
[ 패턴 매칭 ]
- 어떤 식이 특정 패턴과 일치하는지 검사를 하여 일치 여부를 반환한다 .
- 이를 통해 장황한 분기문을 간결하고 가독성 있는 코드로 대체 가능하다 .
[ 식 ]
- 코드에서 단일 결과값을 만들어낼 수 있는 연산자와 연산자의 조합 . d = a+456;
- 리터럴과 상수,변수는 연산자 없이 식이 될 수 있다 . ex) 10 은 단일결과값 10을 만드는 식
[ 식의 패턴 ]
- 식의 패턴 = 식 결과의 패턴
[ 1 . 선언 패턴 ]
- 식이 주어진 형식(int , string )과 일치하는지 테스트
- 테스트가 성공하면(식과 형식이 일치하면) 식을 주어진 형식으로 변환
//is 연산자는 왼쪽에 있는 식이 오른쪽에 있는 패턴과 일치하는지 테스트
object foo = 123;
//1 . foo 가 int 형식과 일치하는지 테스트
//2 . foo를 int 형식으로 변환하여 bar에 할당
if(foo is int bar)
{
Console.WriteLine(bar);
}
[ 2 . 형식 패턴 ]
- 선언패턴과 비슷하게 동작하지만 , 변수 생성 없이 형식 일치 여부만 테스트한다 .
object foo = 23;
if(foo is int)
Console.WriteLine(foo);
class Preschooler{}
class Underage{}
class Adult{}
class Senior{}
internal class MainApp
{
static int CalculateFee(object visitor)
{
return visitor switch
{
Underage = > 100,
Adult => 500 ,
Senior => 200,
_ => throw new ArgumentException(
$"Prohibitited age : {visitor.GetType()}",nameif(visitor)),
};
}
static void Main(string[] args)
{
Console.WriteLine($"Fee for a senior : {CalculateFee(new Senior())}");
Console.WriteLine($"Fee for a adult : {CalculateFee(new Adult())}");
Console.WriteLine($"Fee for a underage : {CalculateFee(new Underage())}");
Console.WriteLine($"Fee for a prescooler : {CalculateFee(new Prescooler())}");
}
}
[ 3 . 상수 패턴 ]
- 식이 특정 상수와 일치하는지 검사한다 .
- 정수 / 문자열 리터럴 뿐 아니라 null , enum등 모든 상수와 매칭 가능 .
var GetCountryCode = (string nation)=>nation switch
{
"KR"=>82,
"US"=>1,
"UK"=>44,
_=>throw new ArgumentException("Not supported code")
};
Console.WriteLine(GetCountryCode("KR"));
- 어떤 객체가 null인지 확인하고 싶다면 ,is 연산자와 함께 상수 패턴 매칭을 사용 할 수 있다 .
if(object is null)
{
// ...
}
if(object is not null)
{
// ...
}
[ 4 . 프로퍼티 패턴 ]
- 식의 속성이나 필드가 패턴과 일치하는지 검사한다 .
- 입력된 식이 int,double과 같은 기본 데이터 형식이 아닌 복합 데이터 형식일 경우 유용하다 .
class Car
{
public string Model{get;set;}
public DateTime ProduceAt{get;set;}
}
static string GetNickname(Car car)
{
var GenerateMessage = (Car car,string nickname)=>
$"{car.Model}produced in {car.ProduceAt.Year} is {nickname}"'
if(car is Car{Model:"Mustang",ProducedAt.Year:1967})
return GenerateMessage(car,"Fastback");
else if(car is Car{Model:"Mustang",ProducedAt.Year:1976})
return GenerateMessage(car,"Cobar 2");
else
return GenerateMessage(car,"Unkown");
}
static void Main(string args)
{
Console.WriteLine(
GetNickName(
new Car(){Model = "Mustang",ProducedAt = new DataTime(196,11,23)}));
}
[ 5 . 관계 패턴 ]
- 관계연산자를 이용하여 입력받은 상수와 비교한다 .
static bool IsPassed(double score) => score switch
{
<60 => false,
_ => true,
}
- 관계 패턴과 이어 논리 패턴의 and를 함께 이용하면 입력받은 식이 특정 범위안에 드는지 테스트도 가능하다 .
static string GetGrade(double score) =>score switch
{
< 60 => "F",
>=60 and < 70 =>"D",
>=70 and <80 => "C",
>=80 and <90 => "B",
_ =>"A"
};
[ 6 . 논리 패턴 ]
- 패턴과 패턴을 패턴 논리 연산자 (and , or, not)을 조합해 하나의 논리패턴으로 만든다 .
class OrderItem
{
public int Amount{get;set;}
public int Price{get;set;}
}
static double GetPrice(OrderItem orderItem)=> orderItem switch
{
OrderItem {Amount : 0}or OrderItem{Price:0}
=> 0.0,
OrderItem{Amount>=100} and OrderItem{Price: >= 10_000}
=>orderItem.Amount * orderItem.Price * 0.8,
not OrderItem{Amount:<100}
=>orderItem.Amount * orderItem.Price * 0.9,
_
=>=>orderItem.Amount * orderItem.Price,
};
statoc void Main(string args[])
{
Console.WriteLine(GetPrice(new OrderItem(){Amount = 0 , Price = 10_000}));
}
[ 7 . 괄호 패턴 ]
- 논리 패턴으로 여러 패턴을 조합한 뒤 이를 새로운 패턴으로 만들때 사용
object age= 30;
if(age is (int and >19))
Console.WriteLine("Major");
[ 8 . 위치 패턴 ]
- 식의 결과를 분해하고 , 분해한 값들이 내장된 복수의 패턴과 일치하는지 검사한다 .
- 위치 패턴안에 내장되는 패턴에는 형식,상수 등 어떤 패턴이든지 올 수 있다 .
- 단, 분해된 값들과 내장된 패턴의 개수,순서가 일치해야 한다 .
Tuple<string , int >itemPrice = new Tuple<string,int>("espresso",3000);
if(itemPrice is ("espresso",<5000))
Console.WriteLine("The coffee is affordable");
struct Audience
{
public bool IsCitizen{get;init;}
public int Age{get;init;}
public Audience(bool isCitizen,int age)
{
IsCitizen= isCitizen;
Age= age;
}
public Deconstrut(out bool isCitizen,out int age)
{
isCitizen=IsCitizen;
age=Age;
}
}
static void Main(string args[])
{
var CalculateFee = (Audience audience)=>audience switch
{
(true,< 19)=>100,
(true,_)=>200,
(false,<19)=>200,
(false,_)=>400,
};
}
var a1 = new Audience(true,10);
Console.WriteLine(
$"내국인 : {a1.Citizen} , 나이 : {a1.Age} , 요금 : {CalculateFee(a1)}";
[ 9 . var 패턴 ]
- null을 포함한 모든 식의 패턴매칭을 성공시키고 , 그 식의 결과를 변수에 할당한다 .
- 어떤 식의 결과를 임시 변수에 할당한 뒤 추가 연산을 수행할때 유용하다 .
var IsPassed =
(int[] scores) => scores.Sum() / scores.Length is var average
&& Array.TrueForAll(scores , (score) => score >= 60)
&& average >=60;
[ 10 . 무시 패턴 ]
- 모든 식과의 패턴 일치 검사를 성공시킨다 .
- var 패턴과 다르게 is 식에서는 사용 불가 ,switch 식에서만 사용 가능하다 .
var GetCountryCode = (string nation)=>nation switch
{
"US"=>1,
"KR"=>82,
"UK"=>44,
_=>throw new ArgumentException("Not Supported Code"),
}
[ 11 . 목록 패턴 ]
- 배열이나 리스트가 패턴의 시퀸스와 일치하는지를 검사한다 .
- 패턴의 시퀸스는 대괄화 [와] 사이에 패턴의 목록을 입력하여 만든다 .
var match = (int[]array)=>array is [int,>10,_];
Console.WriteLine(match(new int[]{1,100,3})); //True
Console.WriteLine(match(new int[]{1,10,3})); //false : 두번째 요소 패턴 시퀸스와 불일치
- 범위 패턴 ..을 함께 사용하면 식으로 입력되는 배열이나 리스트의 길이에 관계없이 패턴 매칭을 수행 할수 있다.
//첫 두요소에 대해서만 패턴이 일치하는지 검사 이후 요소에 대해서는 길이 포함해서 검사 수행 안함
var match = (int[]array)=>array is [int,>10,..]
- 목록 패턴은 다량의 데이터를 처리시 유용하다 .
- 파일이나 데이터베이스에서 레코드를 읽어 처리하는 문제에 찰떡 .
using System;
using System.Collections.Generic;
using System.Net.NetworkInformation;
namespace GoTo;
class MainApp
{
//프로그램 실행이 시작되는 곳
static void Main(string[] args)
{
var GetStatistics = (List<object[]> records) =>
{
var statistics = new Dictionary<string, int>();
foreach (var record in records)
{
var (contentType, contentView) = record switch
{
[_, "COMEDY", .., var views] => ("COMEDY", views),
[_, "SF", .., var views] => ("SF", views),
[_, "Action", .., var views] => ("ACTION", views),
[_, .., var amount] => ("ETC", amount),
_ => ("ETC", 0),
};
if (statistics.ContainsKey(contentType))
statistics[contentType] += (int)contentView;
else
statistics.Add(contentType, (int)contentView);
}
return statistics;
};
List<object[]> MovieRecords = new List<object[]>()
{
new object[]{ 0,"COMEDY","SPY",2015,10_000},
new object[]{ 1,"COMEDY","ScaryMovie",20_000},
new object[]{ 0,"SF","IRON Man",100_000},
new object[]{ 0,"COMEDY","HAHA",25_000},
new object[]{ 0,"SF","Star wars",200_000},
new object[]{ 5,"ACTION","Fast & Furious ",80_000},
new object[]{ 6,"DRAMA","Notting Hill",1_000},
};
var statistics = GetStatistics(MovieRecords);
foreach(var s in statistics)
Console.WriteLine($"{s.Key}:{s.Value}");
}
}
'C# > 이것이 C#이다' 카테고리의 다른 글
[ 이것이 C#이다 ] Chapter 07 . 클래스 (0) | 2024.03.06 |
---|---|
[ 이것이 C#이다 ] Chapter 06 . 메소드로 코드 간추리기 (0) | 2024.03.04 |
[ 이것이 C#이다 ] Chapter 04 . 데이터를 가공하는 연산자 (0) | 2024.02.27 |
[ 이것이 C#이다 ] Chapter 03 . 데이터 보관하기 (0) | 2024.02.15 |
[ 이것이 C#이다 ] Chapter 02 . 처음 만드는 C# 프로그램 (0) | 2024.02.14 |