🚀 고급 C# 문법
지난 시간에는 고급 C# 문법 중 하나인 Async, Await의 개념과 활용에 대해서 학습하였다. 물론 한번 보았다고 모든 걸 다 이해할 수 있는 내용은 아니었지만, 적어도 비동기를 통해 프로세스 주도권을 옮기며 처리하는 개념은 이해하였다. 이번 시간에는 마찬가지로 고급 C# 문법 중 하나인 LINQ에 대해서 학습하도록 하자.
👑 LINQ
LINQ는 RDBMS의 SQL 문법과 굉장히 유사한 부분이 많으며, 데이터를 다룰 때 특히 유용하게 사용되는 개념이다. 이번 시간에는 예제를 통해 LINQ가 왜 중요하고, 언제 유용한지에 대해서 알아보도록 하자.
public enum ClassType
{
Knight,
Archer,
Mage
}
public class Player
{
public ClassType ClassType { get; set; }
public int Level { get; set; }
public int Hp { get; set; }
public int Attack { get; set; }
}
class LINQ
{
static List<Player> _players = new List<Player>();
static void Main(string[] args)
{
Random rand = new Random();
for (int i = 0; i < 100; i++)
{
// 랜덤으로 직업 선택
ClassType type = ClassType.Knight;
switch (rand.Next(0, 3))
{
case 0:
type = ClassType.Knight;
break;
case 1:
type = ClassType.Archer;
break;
case 2:
type = ClassType.Mage;
break;
}
// 플레이어 생성
Player player = new Player()
{
ClassType = type,
Level = rand.Next(1, 100),
Hp = rand.Next(100, 1000),
Attack = rand.Next(10, 100)
};
_players.Add(player);
}
}
}
일반적인 게임으로 예를 들어보도록 하자. 플레이어는 레벨을 가지고 있으며 마찬가지로 체력, 공격력, 직업 또한 가지고 있다. 이러한 플레이어를 랜덤으로 100명을 생성할 것인데 직업과 체력, 레벨, 공격력을 모두 무작위로 설정하여 만들어 준다. 만약 이 상황에서 '레벨이 50 이상인 기사를 낮은 레벨에서 높은 순서대로 정렬하시오.'라는 문제가 생길 경우 어떻게 처리해야 할까?
링큐를 사용하지 않는다면, 이를 처리해야할 함수를 하나 새롭게 만들어 아래와 같이 처리할 수 있을 것이다.
...
class LINQ
{
static List<Player> _players = new List<Player>();
static void Main(string[] args)
{
Random rand = new Random();
for (int i = 0; i < 100; i++)
{
// 랜덤으로 직업 선택
ClassType type = ClassType.Knight;
switch (rand.Next(0, 3))
{
case 0:
type = ClassType.Knight;
break;
case 1:
type = ClassType.Archer;
break;
case 2:
type = ClassType.Mage;
break;
}
// 플레이어 생성
Player player = new Player()
{
ClassType = type,
Level = rand.Next(1, 100),
Hp = rand.Next(100, 1000),
Attack = rand.Next(10, 100)
};
_players.Add(player);
}
List<Player> players = GetHighLevelKnights();
foreach (Player p in players)
{
// 레벨과 체력 출력
Console.WriteLine($"Level: {p.Level}, HP: {p.Hp}");
}
}
static public List<Player> GetHighLevelKnights()
{
List<Player> players = new List<Player>();
foreach (Player player in _players)
{
// 방법 1
if (player.ClassType != ClassType.Knight)
continue;
if (player.Level < 50)
continue;
players.Add(player);
}
players.Sort((lhs, rhs) => { return lhs.Level - rhs.Level; });
return _players;
}
}
먼저 GetHighLevelKnights 함수를 새롭게 만들어주고 players 변수에 Player를 리스트 담아준 뒤, foreach문을 순회하며 조건에 맞는 데이터를 처리한다. 하지만 이렇게 처리할 경우 개발자에 따라 주석 처리한 '방법 1'과 같이 처리하는 개발자가 있을 것이며 이와는 다른 방식으로 처리하는 개발자가 있을 것이다. 하지만 위 함수가 주석도 없고, 라이브로 돌아가는 서비스에 위 함수와 유사한 코드들이 많을 경우 이를 하나하나씩 분석하기에는 힘들것이다.
이제 위 함수와 똑같이 동작하는 내용을 LINQ로 구현해보자.
// LINQ 버전
{
var players =
from p in _players
where p.ClassType == ClassType.Knight && p.Level >= 50
orderby p.Level
select p;
// select new { Hp = p.Hp, Level = p.Level * 2 };
foreach (Player p in players)
{
// 레벨과 체력 출력
Console.WriteLine($"Level: {p.Level}, HP: {p.Hp}");
}
}
처음보면 굉장히 생소하지만, 코드를 보면 장점이 뚜렷하게 보이는 것을 볼 수 있다. 일전에 배운 SQL과 같이 select, from, where, orderby를 사용하여 코드를 작성한 것을 볼 수 있다.
각각의 기능을 하나씩 차근차근 알아보도록 하자. from은 일전에 구현한 함수 GetHighLevelKnights의 foreach와 동일한 기능을 하고, where은 일종의 필터 역할을 한다. 따라서 조건에 부합하는 데이터만 걸러낼 수 있다. order by는 정렬을 수행한다. 기본적으로 오름차순을 진행하며 오름차순은 ascending, 내림차순은 descending 뜻한다. select는 최종 결과물을 추출한다. 보다 심화적으로 처리할 경우 주석처리한 내용과 같이 가공해서 추출할 수도 있다.
따라서 링크의 장점은 코드량이 굉장히 적어지고, 모두가 비슷한 형태의 코드를 작성하여 가독성이 높아지는 것을 알 수 있다. 또한 링크를 배운다면 이를 기반으로 한 기술이 굉장히 많아 추후 유리하기도 하다.
'공부 > 인프런 - Rookiss' 카테고리의 다른 글
Part 6-4-1. ASP.NET Core 둘러보기 : 환경설정 (0) | 2024.08.24 |
---|---|
Part 6-3-3. 고급 C# 문법 : LINQ #2 (0) | 2024.08.23 |
Part 6-3-1. 고급 C# 문법 : Async, Await (0) | 2024.08.17 |
Part 6-2-9. 웹 기초 : CSS #2 (0) | 2024.08.17 |
Part 6-2-8. 웹 기초 : CSS #1 (0) | 2024.08.13 |