본문으로 바로가기
제품데스크톱 도구TASTECAD도면 확인TASTEFILES파일 관리TASTEFTP파일 전송TASTESSH원격 작업공간TASTEZIP압축과 해제개발 도구TASTECODERust 통합 개발 환경TASTESTUDIO통합 개발·테스트 환경TASTEETL데이터 통합(ETL)서버TASTEREMOTE원격 데스크톱 서버TASTEGEO공간정보 서버TASTEMAIL메일 작업공간시작하기다운로드문서구매모든 제품
마켓플레이스
소식
개발소식오늘의 개발 소식개발 문서프로그래밍 언어RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDart프런트엔드 프레임워크Next.jsReactVue.js · NuxtSvelteKitAngular서버 프레임워크Spring BootDjangoFastAPIASP.NET CoreNestJS · Express앱 · 데스크톱 프레임워크TauriFlutterReact NativeElectron알고리즘알고리즘 기초알고리즘 핵심알고리즘 심화실무 알고리즘
커뮤니티프로젝트개발 로그프롬프트AI 도구 이슈쇼케이스커뮤니티 안내
협업기술 전수홈페이지 구축데스크톱 앱 구축릴리스·결제 파이프라인판매 파트너문의
서비스원격 데스크톱설치 패키지 커스텀
TASTEDEV
제품

데스크톱 도구

TASTECAD복잡한 도면을 가볍게 열다TASTEFILES필요한 파일만, 가장 빠르게TASTEFTP파일이 오가는 가장 단정한 길TASTESSH서버와 나 사이, 더 단단한 연결TASTEZIP더 빠르게 묶고, 더 안전하게 풀다

개발 도구

TASTECODERust 앱을 편집 · 빌드 · 디버깅 · 테스트까지 한 창에서TASTESTUDIO편집부터 원격 테스트와 승인 기반 AI 수정까지TASTEETL값을 보며 데이터를 옮깁니다

서버

TASTEREMOTE우리 회사 서버로 운영하는 원격 데스크톱TASTEGEOGeoServer 호환 공간정보 서버를 Rust로 다시 세웁니다TASTEMAIL메일의 주도권을 다시 내 손에

시작하기

다운로드모든 제품 최신 판문서제품 사용법구매구독 · 영구 라이선스모든 제품모든 제품 한눈에
모든 제품
마켓플레이스소식
개발

소식

오늘의 개발 소식언어 · 프레임워크 · GitHub · AI 공식 발표개발 문서언어 · 프레임워크 · 알고리즘 안내서

프로그래밍 언어

RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDart

프레임워크

프런트엔드 프레임워크Next.jsReactVue.js · NuxtSvelteKitAngular
서버 프레임워크Spring BootDjangoFastAPIASP.NET CoreNestJS · Express
앱 · 데스크톱 프레임워크TauriFlutterReact NativeElectron

알고리즘

알고리즘 기초복잡도 분석 · 정렬 · 탐색 · 기본 자료구조 · 트리와 힙알고리즘 핵심그래프 탐색 · 최단 경로와 최소 신장 트리 · 동적 계획법 · 탐욕 알고리즘 · 분할 정복 · 백트래킹알고리즘 심화문자열 알고리즘 · 수학과 정수론 · 비트 연산 · 구간 트리 · 유니온 파인드실무 알고리즘코딩 면접 풀이 전략 · LRU 캐시 · 레이트 리미터 · 일관된 해시
개발 문서 전체 보기
커뮤니티
프로젝트빌더와 작업 발견개발 로그결정과 시행착오프롬프트재사용 가능한 지시AI 도구 이슈Claude · Codex · Gemini 문제와 우회법쇼케이스완성된 결과커뮤니티 안내공개하고 함께 만드는 방식
협업
기술 전수Rust·egui 네이티브 앱 만들기홈페이지 구축10개 언어, 계정, 문서·다운로드데스크톱 앱 구축Rust·egui, WebView 없이릴리스·결제 파이프라인서명 · MSI·deb·rpm·AppImage · 해시판매 파트너소개하고 결제액의 30% 받기문의구축 · 제휴 · 투자 문의
서비스
원격 데스크톱브라우저로 내 컴퓨터에 접속설치 패키지 커스텀필요한 기능만, 설정은 미리
구매
KO
한국어EnglishDeutschEspañolFrançaisItalianoPortuguês (Brasil)日本語简体中文繁體中文
로그인
로그인
TASTEDEV

작은 도구부터, 더 좋은 개발까지.

support@tastedev.netTASTEDEV 후원하기
제품제품군구매문서다운로드마켓플레이스고객 지원
커뮤니티프로젝트개발 로그프롬프트AI 도구 이슈쇼케이스
정책개인정보처리방침이용약관구독 약관환불 정책커뮤니티 운영 정책
계정로그인가입하기
방문자
오늘
012345678901234567890123456789012345678901234567890123456789
어제
012345678901234567890123456789012345678901234567890123456789
누적 조회
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
상호
지엑스소프트
대표자
최영구
사업자등록번호
853-44-00368
주소
인천광역시 미추홀구 경인로 351 9층 V24
전화
+82-10-4404-1523
이메일
whitecalvin@tastedev.net
개인정보 보호책임자
최영구

© 2026 TASTEDEV제품 정보는 현재 검증된 개발 소스를 기준으로 합니다.출시·고도화 중

C# 문서
C#
C# 시작하기기본 문법타입과 데이터프로젝트와 패키지오류 처리와 테스트핵심 개념: LINQ, 델리게이트, 비동기
토론

C# 안내서 · 3/6

타입과 데이터

C#의 모든 값은 타입을 가지며, 타입은 크게 값 형식과 참조 형식으로 나뉩니다. 이 차이를 이해하면 대입, 메서드 호출, 비교가 어떻게 동작하는지 예측할 수 있습니다. 이 장에서는 두 형식의 차이, 클래스 · 구조체 · 레코드, 속성, 자주 쓰는 컬렉션, 그리고 null을 안전하게 다루는 방법을 살펴봅니다.

값 형식과 참조 형식

int, double, bool, decimal, DateTime 같은 기본 타입과 struct, enum은 값 형식입니다. 변수에 값 자체가 들어 있어서 대입하면 값이 복사됩니다. 반면 class, string, 배열, 레코드 클래스는 참조 형식입니다. 변수에는 객체를 가리키는 참조가 들어 있어서 대입하면 같은 객체를 함께 가리키게 됩니다.

var p1 = new PointStruct { X = 1 };
var p2 = p1;          // 값이 복사됩니다
p2.X = 99;
Console.WriteLine(p1.X); // 1

var c1 = new PointClass { X = 1 };
var c2 = c1;          // 참조가 복사됩니다
c2.X = 99;
Console.WriteLine(c1.X); // 99

struct PointStruct { public int X; }
class PointClass { public int X; }

string은 참조 형식이지만 한 번 만든 문자열은 바뀌지 않는(불변) 객체이고, ==가 내용을 비교하므로 값처럼 다룰 수 있습니다. 구조체는 작고 불변인 데이터(좌표, 금액 등)에 알맞고, 대부분의 경우에는 클래스를 씁니다.

클래스와 속성

클래스는 데이터(필드 · 속성)와 동작(메서드)을 함께 묶습니다. 바깥에 공개할 데이터는 필드 대신 속성으로 노출하는 것이 관례입니다. 속성은 get · set 접근자를 가진 멤버로, 나중에 검증 로직을 넣어도 사용하는 쪽 코드는 바뀌지 않습니다.

var account = new Account("김하늘") { Number = "110-123-456" };
account.Deposit(50_000m);
Console.WriteLine($"{account.Owner}: {account.Balance:N0}원");

public class Account
{
    private decimal _balance;

    public Account(string owner) => Owner = owner;

    public string Owner { get; }              // 읽기 전용 속성
    public string? Memo { get; set; }         // 자동 구현 속성
    public required string Number { get; init; } // 생성할 때만 정할 수 있는 필수 속성

    public decimal Balance => _balance;       // 계산 속성

    public void Deposit(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentOutOfRangeException(nameof(amount), "입금액은 0보다 커야 합니다.");
        _balance += amount;
    }
}

init 접근자는 객체 초기화 식({ Number = ... })에서만 값을 넣을 수 있게 하고, required는 그 값을 빠뜨리면 컴파일 오류를 냅니다. 숫자 리터럴의 _는 자릿수 구분용이며 값에는 영향이 없습니다.

레코드

레코드는 데이터를 담는 것이 주목적인 타입을 짧게 선언하는 방법입니다. 위치 매개변수로 선언하면 생성자, 읽기 전용 속성, 값 기반 같음 비교, 보기 좋은 ToString이 자동으로 만들어집니다.

var a = new Product("마우스", 25_000m);
var b = new Product("마우스", 25_000m);

Console.WriteLine(a == b);   // True: 내용이 같으면 같습니다
Console.WriteLine(a);        // Product { Name = 마우스, Price = 25000 }

var discounted = a with { Price = 20_000m }; // 일부만 바꾼 복사본

public record Product(string Name, decimal Price);

with 식은 원본을 바꾸지 않고 일부 속성만 다른 새 레코드를 만듭니다. record는 기본적으로 참조 형식이며, 값 형식이 필요하면 record struct로 선언합니다.

컬렉션

가장 많이 쓰는 컬렉션은 System.Collections.Generic 네임스페이스의 List<T>와 Dictionary<TKey, TValue>입니다. 꺾쇠 안의 타입 매개변수 덕분에 어떤 타입의 값을 담는지 컴파일러가 확인합니다.

List<string> langs = ["C#", "F#", "Rust"];   // 컬렉션 식
langs.Add("Go");
langs.Remove("F#");
Console.WriteLine($"{langs.Count}개, 첫 번째: {langs[0]}");

var stock = new Dictionary<string, int>
{
    ["사과"] = 10,
    ["배"] = 4,
};
stock["귤"] = 7;                 // 추가하거나 덮어씁니다

if (stock.TryGetValue("배", out var pears))
    Console.WriteLine($"배 재고: {pears}");

foreach (var (fruit, qty) in stock)
    Console.WriteLine($"{fruit} = {qty}");

없는 키를 인덱서(stock["감"])로 읽으면 KeyNotFoundException이 발생하므로, 있는지 모를 때는 TryGetValue나 ContainsKey를 씁니다. 이 밖에 중복 없는 집합 HashSet<T>, 선입선출 Queue<T>, 후입선출 Stack<T>도 자주 쓰입니다. 크기가 정해진 데이터는 배열(int[])로 다룹니다.

null 허용 참조 형식

프로젝트 파일에 <Nullable>enable</Nullable>이 켜져 있으면, 컴파일러는 참조 형식 변수에 null이 들어갈 수 있는지 추적합니다. string은 null이 아니라는 뜻이고, null을 허용하려면 string?처럼 물음표를 붙입니다. null일 수 있는 값을 확인 없이 쓰면 경고가 나옵니다.

string? FindNickname(int userId) => userId == 1 ? "하늘" : null;

string? nick = FindNickname(2);

Console.WriteLine(nick?.Length);          // null 이면 null (예외 없음)
Console.WriteLine(nick ?? "(별명 없음)");   // null 이면 오른쪽 값
nick ??= "손님";                            // null 일 때만 대입

if (nick is not null)
    Console.WriteLine(nick.ToUpper());     // 여기서는 null 이 아님을 압니다

int? age = null;                           // null 허용 값 형식
Console.WriteLine(age.HasValue ? age.Value : -1);

?.는 null이면 멤버 접근을 건너뛰고, ??는 기본값을 주고, ??=는 비어 있을 때만 채웁니다. 값이 null이 아님을 확신할 때 !(null 용서 연산자)로 경고를 끌 수 있지만, 실제 검사를 하지는 않으므로 아껴 써야 합니다.

정리

  • 값 형식은 대입할 때 값이, 참조 형식은 참조가 복사됩니다.
  • 클래스는 속성과 메서드로 데이터와 동작을 묶고, init · required로 생성 규칙을 표현합니다.
  • 레코드는 값 기반 비교와 with 식을 제공하는 데이터 중심 타입입니다.
  • List<T>와 Dictionary<TKey, TValue>가 기본 컬렉션이며, 키 조회에는 TryGetValue를 씁니다.
  • null 허용 참조 형식을 켜 두면 string?, ?., ??로 null 오류를 컴파일 단계에서 줄일 수 있습니다.
이 장에 대해 질문이 있나요?
이전 장기본 문법다음 장프로젝트와 패키지

댓글 0개

인기 댓글순최신순

로그인 · 로그인하면 댓글을 남길 수 있습니다.