.NET Core 기초 개념: C# 문법과 CLR 런타임 핵심 정리

.NET Core 기초 개념
📚
학습 포인트

.NET Core 기초 개념

.NET Core의 핵심 개념과 C# 기초 문법을 복습하여 Blazor 학습의 토대를 만듭니다.

📌 학습 목표

이 글을 완독하면 다음을 수행할 수 있습니다.

  • .NET Core의 탄생 배경과 핵심 특징을 설명할 수 있습니다.
  • CLR(공통 언어 런타임)과 JIT 컴파일의 동작 원리를 이해할 수 있습니다.
  • C# 변수, 데이터 타입, 제어 흐름을 활용한 기본 코드를 작성할 수 있습니다.
  • 클래스와 네임스페이스 개념을 이해하고 실제 코드에 적용할 수 있습니다.
  • Blazor 개발에 직접 연결되는 C# 핵심 개념의 기초를 완성할 수 있습니다.

📝 .NET Core란 무엇인가?

탄생 배경과 역사

Microsoft는 2002년 .NET Framework를 출시하였습니다. Windows 전용으로 설계된 강력한 플랫폼이었지만, 모바일·클라우드 환경이 부상하면서 크로스플랫폼 지원의 필요성이 대두되었습니다.

 

이에 Microsoft는 2016년 .NET Core 1.0을 발표하며 오픈소스·크로스플랫폼 전략으로 전환하였습니다. 2020년 .NET 5부터는 ‘Core’ 접미사를 제거하고 단순히 .NET으로 통합되었으며, 현재(2024년 기준) 최신 LTS 버전은 .NET 8입니다.

.NET의 핵심 특징

  • 크로스플랫폼(Cross-Platform): Windows, macOS, Linux 모두에서 동일한 코드를 실행할 수 있습니다.
  • 오픈소스(Open Source): GitHub에서 소스 코드를 확인하고 기여할 수 있습니다.
  • 고성능(High Performance): ASP.NET Core는 세계 최상위권 웹 프레임워크 벤치마크 성능을 자랑합니다.
  • 모듈형 아키텍처: 필요한 NuGet 패키지만 선택적으로 포함하여 경량 배포가 가능합니다.
  • CLI 우선(CLI-First): dotnet CLI를 통해 IDE 없이도 프로젝트 생성·빌드·실행이 가능합니다.

 

 

⚖️ .NET Framework vs .NET Core vs .NET 5+

 

항목.NET Framework.NET Core.NET 5+
출시 시기2002년2016년2020년~
플랫폼Windows 전용크로스플랫폼크로스플랫폼
오픈소스부분 공개완전 공개완전 공개
배포 방식Windows 내장독립 배포 가능독립 배포 가능
현재 상태유지보수만.NET 5로 통합현재 주력

📝 .NET 런타임 핵심 개념

CLR(Common Language Runtime) — 공통 언어 런타임

CLR은 .NET 애플리케이션이 실행되는 가상 머신(Virtual Machine) 역할을 합니다. C# 코드는 CLR 위에서 관리되는 코드(Managed Code)로 동작하며, 메모리 안전성과 타입 안전성을 CLR이 보장합니다.

 

 

🔄 C# 코드 실행 흐름

 

C# 소스 코드
(.cs 파일)
Roslyn 컴파일러
IL 코드
(.dll 파일)
JIT 컴파일러
(CLR)
네이티브 코드
(CPU 실행)
  • IL(Intermediate Language) 코드: C# 컴파일러는 소스 코드를 OS에 독립적인 중간 언어로 변환합니다. .dll 파일에 담깁니다.
  • JIT(Just-In-Time) 컴파일: CLR이 IL 코드를 실행 시점에 해당 플랫폼의 네이티브 기계어로 변환합니다. 첫 실행 후에는 캐싱되어 재사용됩니다.
  • 가비지 컬렉션(Garbage Collection): 더 이상 참조되지 않는 객체의 메모리를 CLR이 자동으로 회수합니다. 개발자가 직접 메모리를 해제할 필요가 없습니다.
  • 타입 안전성(Type Safety): 잘못된 타입 변환이나 배열 범위 초과 접근을 CLR이 감지하여 예외를 발생시킵니다.

📝 C# 기초 문법

변수와 데이터 타입

C#은 정적 타입(Statically Typed) 언어입니다. 변수 선언 시 타입을 명시하거나, var 키워드로 컴파일러에 타입 추론을 맡길 수 있습니다.

// 값 형식 (Value Types) — 스택에 저장
int age = 30;
double salary = 5_000_000.50;   // 숫자 구분자 지원
bool isActive = true;
char grade = 'A';

// 참조 형식 (Reference Types) — 힙에 저장
string name = "홍길동";
string[] hobbies = { "독서", "코딩", "등산" };

// var 타입 추론 (컴파일 시점 타입 고정)
var city = "서울";    // → string
var count = 100;      // → int

// Nullable: 값 형식에 null 허용
int? nullableScore = null;
nullableScore = 85;

문자열 보간과 자주 쓰는 연산

string firstName = "길동";
string lastName = "홍";

// 문자열 보간 ($ 접두사)
string fullName = $"{lastName}{firstName}";
Console.WriteLine($"이름: {fullName}, 길이: {fullName.Length}자");

// 자주 쓰는 string 메서드
string msg = "  Hello, Blazor!  ";
Console.WriteLine(msg.Trim());           // 공백 제거
Console.WriteLine(msg.ToUpper());        // 대문자 변환
Console.WriteLine(msg.Contains("Blazor")); // 포함 여부
Console.WriteLine(msg.Replace("Blazor", ".NET")); // 치환

제어 흐름 — 조건문과 반복문

// if-else 조건문
int score = 85;
string grade;
if (score >= 90)
    grade = "A";
else if (score >= 80)
    grade = "B";
else
    grade = "C 이하";

// switch 표현식 (C# 8.0+)
string gradeLabel = score switch
{
    >= 90 => "우수",
    >= 80 => "양호",
    >= 70 => "보통",
    _     => "미흡"
};
Console.WriteLine(gradeLabel);   // 출력: 양호

// for 반복문
for (int i = 1; i <= 5; i++)
    Console.Write($"{i} ");      // 출력: 1 2 3 4 5

// foreach — 컬렉션 순회
string[] langs = { "C#", "Python", "TypeScript" };
foreach (string lang in langs)
    Console.WriteLine(lang);

// while
int n = 10;
while (n > 0)
    n -= 3;

메서드(Method)

메서드는 특정 작업을 수행하는 재사용 가능한 코드 블록입니다. 접근 제한자 + 반환 타입 + 메서드명(매개변수) 형태로 선언합니다.

// 기본 메서드
public int Add(int a, int b)
{
    return a + b;
}

// void: 반환값 없음
public void Greet(string name)
{
    Console.WriteLine($"안녕하세요, {name}님!");
}

// 선택적 매개변수 (기본값 지정)
public void CreateUser(string name, int age = 20, string role = "User")
{
    Console.WriteLine($"[{role}] {name} ({age}세) 등록 완료");
}

// 람다 표현식
Func<int, int, int> multiply = (x, y) => x * y;
Console.WriteLine(multiply(4, 5));   // 출력: 20

클래스와 객체 지향

C#은 객체 지향 언어(Object-Oriented Language)입니다. 클래스는 데이터(프로퍼티)와 동작(메서드)을 묶는 설계도이며, 객체는 그 설계도로 만들어진 실체입니다.

// 클래스 선언
public class Person
{
    // 자동 구현 프로퍼티
    public string Name { get; set; }
    public int Age  { get; set; }

    // 생성자
    public Person(string name, int age)
    {
        Name = name;
        Age  = age;
    }

    // 메서드
    public string Introduce() =>
        $"저는 {Name}이고 {Age}살입니다.";
}

// 객체 생성 및 사용
Person p1 = new Person("김철수", 25);
Console.WriteLine(p1.Introduce());

// C# 9.0+ 간결 표기
Person p2 = new("이영희", 30);

네임스페이스(Namespace)

네임스페이스는 관련 클래스와 타입을 논리적으로 그룹화합니다. Blazor 프로젝트에서도 컴포넌트를 네임스페이스로 체계적으로 관리합니다.

// 네임스페이스 선언
namespace MyApp.Models
{
    public class Product
    {
        public int Id       { get; set; }
        public string Name  { get; set; }
        public decimal Price { get; set; }
    }
}

// 다른 파일에서 가져오기
using MyApp.Models;

var product = new Product { Id = 1, Name = "노트북", Price = 1_200_000m };

// C# 10+ 전역 using — Program.cs 상단에 한 번만
global using System;
global using MyApp.Models;

💡 예제 & 실습 — 실행 가능한 .NET 프로그램

Step 1: 프로젝트 생성 및 실행

# 콘솔 앱 프로젝트 생성
dotnet new console -n GradeManager

# 프로젝트 폴더 이동
cd GradeManager

# 실행
dotnet run

Step 2: 학생 성적 관리 프로그램 (종합 예제)

지금까지 배운 클래스·리스트·메서드·LINQ를 종합한 실행 가능한 프로그램입니다. Program.cs를 아래 내용으로 교체하세요.

using System;
using System.Collections.Generic;
using System.Linq;

namespace GradeManager
{
    public class Student
    {
        public string Name   { get; set; }
        public List<int> Scores { get; set; } = new();

        public Student(string name) { Name = name; }

        public double GetAverage() =>
            Scores.Count == 0 ? 0 : Scores.Average();

        public string GetGrade() => GetAverage() switch
        {
            >= 90 => "A",
            >= 80 => "B",
            >= 70 => "C",
            >= 60 => "D",
            _     => "F"
        };

        public void PrintReport()
        {
            Console.WriteLine($"학생: {Name}");
            Console.WriteLine($"점수: {string.Join(", ", Scores)}");
            Console.WriteLine($"평균: {GetAverage():F1}점  학점: {GetGrade()}");
            Console.WriteLine("──────────────────");
        }
    }

    class Program
    {
        static void Main()
        {
            var students = new List<Student>
            {
                new Student("김민준") { Scores = { 95, 88, 92 } },
                new Student("이서연") { Scores = { 75, 82, 70 } },
                new Student("박지호") { Scores = { 60, 55, 65 } }
            };

            Console.WriteLine("===== 성적표 =====");
            foreach (var s in students)
                s.PrintReport();

            // LINQ로 최고 성적 학생 찾기
            var top = students.OrderByDescending(s => s.GetAverage()).First();
            Console.WriteLine($"최고 성적: {top.Name} ({top.GetAverage():F1}점)");
        }
    }
}
단계별 해설
  1. Student 클래스에 NameScores 프로퍼티를 정의하고 생성자로 초기화합니다.
  2. GetAverage()LINQ의 Average()로 점수 평균을 계산합니다.
  3. GetGrade()는 switch 표현식으로 평균에 따른 학점을 반환합니다.
  4. Main()에서 학생 목록을 생성하고 foreach로 성적표를 출력합니다.
  5. LINQ의 OrderByDescending().First()으로 최고 성적 학생을 찾습니다.

 

 

📌 C# 핵심 개념 한눈에

 

🏗️
값 형식 vs 참조 형식
int·bool·struct는 스택 저장. string·class·array는 힙 저장. 동작 방식과 복사 의미론이 다릅니다.
⚙️
CLR & JIT
C# 코드는 IL로 컴파일되고 런타임에 JIT가 네이티브 코드로 변환합니다. 덕분에 한 번의 빌드로 여러 플랫폼에서 실행됩니다.
🔑
프로퍼티
{ get; set; } 자동 구현 프로퍼티가 Blazor 컴포넌트의 [Parameter]와 데이터 바인딩의 핵심입니다.
📦
네임스페이스
using으로 다른 네임스페이스를 가져옵니다. Blazor에서는 @using으로 Razor 파일에 동일하게 적용됩니다.

⚠️ 자주 틀리는 것 / 주의사항

1. .NET Framework와 .NET(Core) 혼동

.NET Framework(구형, Windows 전용)와 .NET 5+(신형, 크로스플랫폼)는 별개의 플랫폼입니다. NuGet 패키지 호환성이 다를 수 있으므로, 프로젝트 파일(.csproj)의 <TargetFramework>net8.0</TargetFramework> 항목을 반드시 확인하십시오.

2. string은 불변(Immutable) — 반복 결합 시 StringBuilder 사용

string += 패턴을 루프에서 반복하면 매번 새로운 객체가 생성되어 성능이 저하됩니다.

// 비효율 (루프 수백 번 시 문제)
string result = "";
for (int i = 0; i < 1000; i++)
    result += i;

// 효율적
var sb = new System.Text.StringBuilder();
for (int i = 0; i < 1000; i++)
    sb.Append(i);
string result2 = sb.ToString();

3. var는 동적 타입이 아닙니다

C#의 var는 JavaScript의 var와 달리 컴파일 시점에 타입이 고정됩니다. 선언 이후 다른 타입의 값을 할당하면 컴파일 오류가 발생합니다.

var count = 10;     // int로 고정
// count = "열";   // ❌ 컴파일 오류: string을 int에 할당 불가

4. Null 참조 예외(NullReferenceException) 주의

참조 형식 변수가 null인 상태에서 멤버에 접근하면 예외가 발생합니다. ?.(null 조건 연산자)와 ??(null 병합 연산자)를 적극 활용하십시오.

string? name = null;

// ❌ NullReferenceException 발생
// Console.WriteLine(name.Length);

// ✅ null 조건 연산자: null이면 null 반환
Console.WriteLine(name?.Length);

// ✅ null 병합 연산자: null이면 기본값 반환
Console.WriteLine(name ?? "이름 없음");

5. 정수 나눗셈 주의

두 정수를 나누면 결과도 정수(소수점 버림)입니다. 실수 결과가 필요하면 한쪽을 double로 캐스팅하십시오.

int a = 7, b = 2;
Console.WriteLine(a / b);           // 출력: 3 (소수점 버림)
Console.WriteLine((double)a / b);   // 출력: 3.5

🎯 마무리

.NET Core(현재 .NET 5+)는 크로스플랫폼·고성능·오픈소스라는 강점으로 현대 애플리케이션 개발의 핵심 플랫폼으로 자리잡았습니다. CLR이 제공하는 JIT 컴파일과 가비지 컬렉션 덕분에 개발자는 메모리 관리보다 비즈니스 로직에 집중할 수 있습니다.

 

C# 기초 문법—변수와 타입, 제어 흐름, 클래스, 네임스페이스—은 Blazor 컴포넌트 개발의 직접적인 토대입니다. 특히 클래스의 프로퍼티는 Blazor의 [Parameter] 속성으로, LINQ는 리스트 데이터 바인딩 처리에, 네임스페이스의 using은 Razor 파일의 @using으로 그대로 연결됩니다. 이 개념들을 탄탄히 익혀두면 Blazor의 문법이 훨씬 자연스럽게 느껴질 것입니다.

✅ 핵심 정리
  • .NET Core(현 .NET 5+)는 크로스플랫폼·오픈소스·고성능 개발 플랫폼으로, Blazor의 런타임 기반입니다.
  • C# 소스 코드 → IL 코드 → JIT 컴파일 → 네이티브 코드 순서로 실행됩니다.
  • CLR의 가비지 컬렉션이 메모리를 자동 관리하므로 개발자는 메모리 해제를 직접 처리하지 않아도 됩니다.
  • 값 형식(int·bool·struct)은 스택, 참조 형식(string·class·array)은 힙에 저장됩니다.
  • var는 컴파일 시점 타입 추론이며, 선언 이후 타입이 변경되지 않습니다.
  • ?.(null 조건)·??(null 병합) 연산자로 NullReferenceException을 사전에 방지하십시오.
  • 클래스의 프로퍼티, 네임스페이스, LINQ는 Blazor 컴포넌트 개발에 직접 활용되는 핵심 개념입니다.

댓글 남기기

Wordpress Social Share Plugin powered by Ultimatelysocial
Copy link
URL has been copied successfully!
THREADS
RSS
error: 저작권 콘텐츠보호를 부탁드립니다.