PHpullh
심층 가이드/C#/객체지향

C# · 심층 가이드

C# 객체지향 완전 정리

클래스와 구조체, record의 차이를 축으로 생성자, 상속, 인터페이스, 불변 객체, 빌더, 의존성 주입까지 C# 객체지향 설계 스무 가지를 코드로 비교합니다.

주제 20개 · 예제 코드 포함 · 최종 수정 2026-08-30 · 작성 pullh 편집팀

객체지향이라는 단어 하나로 묶기에 C#의 타입 선택지는 꽤 넓습니다. 참조로 오가는 class, 값으로 복사되는 struct, 그리고 값 동등성과 with 식을 기본으로 갖춘 record가 각각 다른 문제를 풉니다. 자바나 파이썬에서 넘어온 사람이 가장 자주 걸리는 부분도 여기입니다. 상속 계층을 어떻게 짤지 고민하기 전에, 이 타입이 정체성으로 비교되는지 값으로 비교되는지부터 정하는 편이 순서에 맞습니다.

기본 클래스 또는 구조체생성자와 초기화로 뼈대를 세운 다음, 불변 데이터 객체값 객체 비교를 이어서 보면 record가 왜 등장했는지 자연스럽게 드러납니다. 변경 불가능 업데이트는 그 연장선에서 기존 인스턴스를 건드리지 않고 새 값을 만드는 방식이고, 반대로 생성 인자가 많아 손이 무거워질 때 빌더 패턴이 대안이 됩니다. 상속 또는 확장합성으로 기능 묶기는 같은 요구를 다르게 푼 짝이니 나란히 두고 읽으면 좋습니다.

record의 with는 얕은 복사입니다. 안에 리스트나 배열이 들어 있으면 새 인스턴스와 원본이 같은 컬렉션을 가리키므로, 한쪽에서 항목을 추가하면 다른 쪽에도 보입니다. 불변이라 믿고 공유하다가 생기는 버그가 대부분 여기서 나옵니다. 확장 스타일 동작도 성질을 알아 둘 만합니다. 확장 메서드는 정적 메서드를 문법적으로 바꿔 부르는 것이라, 인스턴스가 null이어도 호출 자체는 성공하고 예외는 메서드 안에서 납니다.

01기본 클래스 또는 구조체

C#에서 기본 클래스 또는 구조체 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 기본 클래스 또는 구조체
using System;

public class User { public User(string name, int level) { Name = name; Level = level; } public string Name { get; } public int Level { get; } }
Console.WriteLine(new User("Ada", 1).Name);
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

02생성자와 초기화

C#에서 생성자와 초기화 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 생성자와 초기화
using System;

public record Profile(string Name, string[] Tags);
Console.WriteLine(new Profile("Ada", new[] { "cs" }));
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

03인스턴스 메서드

C#에서 인스턴스 메서드 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 인스턴스 메서드
using System;

public class User { public User(string name, int level) { Name = name; Level = level; } public string Name { get; } public int Level { get; } }
Console.WriteLine(new User("Ada", 3).Name);
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

04정적 메서드

C#에서 정적 메서드 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 정적 메서드
using System;

public record Profile(string Name, string[] Tags);
Console.WriteLine(new Profile("Ada", new[] { "cs" }));
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

05상속 또는 확장

C#에서 상속 또는 확장 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 상속 또는 확장
using System;

public class User { public User(string name, int level) { Name = name; Level = level; } public string Name { get; } public int Level { get; } }
Console.WriteLine(new User("Ada", 5).Name);
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

06인터페이스 또는 trait

C#에서 인터페이스 또는 trait 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 인터페이스 또는 trait
using System;

public record Profile(string Name, string[] Tags);
Console.WriteLine(new Profile("Ada", new[] { "cs" }));
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

07캡슐화

C#에서 캡슐화 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 캡슐화
using System;

public class User { public User(string name, int level) { Name = name; Level = level; } public string Name { get; } public int Level { get; } }
Console.WriteLine(new User("Ada", 7).Name);
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

08합성으로 기능 묶기

C#에서 합성으로 기능 묶기 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 합성으로 기능 묶기
using System;

public record Profile(string Name, string[] Tags);
Console.WriteLine(new Profile("Ada", new[] { "cs" }));
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

09팩터리 메서드

C#에서 팩터리 메서드 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 팩터리 메서드
using System;

public class User { public User(string name, int level) { Name = name; Level = level; } public string Name { get; } public int Level { get; } }
Console.WriteLine(new User("Ada", 9).Name);
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

10열거형 상태 표현

C#에서 열거형 상태 표현 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 열거형 상태 표현
using System;

public record Profile(string Name, string[] Tags);
Console.WriteLine(new Profile("Ada", new[] { "cs" }));
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

11불변 데이터 객체

C#에서 불변 데이터 객체 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 불변 데이터 객체
using System;

public class User { public User(string name, int level) { Name = name; Level = level; } public string Name { get; } public int Level { get; } }
Console.WriteLine(new User("Ada", 11).Name);
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

12빌더 패턴

C#에서 빌더 패턴 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 빌더 패턴
using System;

public record Profile(string Name, string[] Tags);
Console.WriteLine(new Profile("Ada", new[] { "cs" }));
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

13다형성

C#에서 다형성 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 다형성
using System;

public class User { public User(string name, int level) { Name = name; Level = level; } public string Name { get; } public int Level { get; } }
Console.WriteLine(new User("Ada", 13).Name);
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

14의존성 주입

C#에서 의존성 주입 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 의존성 주입
using System;

public record Profile(string Name, string[] Tags);
Console.WriteLine(new Profile("Ada", new[] { "cs" }));
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

15값 객체 비교

C#에서 값 객체 비교 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 값 객체 비교
using System;

public class User { public User(string name, int level) { Name = name; Level = level; } public string Name { get; } public int Level { get; } }
Console.WriteLine(new User("Ada", 15).Name);
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

16저장소 객체

C#에서 저장소 객체 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 저장소 객체
using System;

public record Profile(string Name, string[] Tags);
Console.WriteLine(new Profile("Ada", new[] { "cs" }));
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

17서비스 객체

C#에서 서비스 객체 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 서비스 객체
using System;

public class User { public User(string name, int level) { Name = name; Level = level; } public string Name { get; } public int Level { get; } }
Console.WriteLine(new User("Ada", 17).Name);
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

18DTO 매핑

C#에서 DTO 매핑 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// DTO 매핑
using System;

public record Profile(string Name, string[] Tags);
Console.WriteLine(new Profile("Ada", new[] { "cs" }));
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

19변경 불가능 업데이트

C#에서 변경 불가능 업데이트 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 변경 불가능 업데이트
using System;

public class User { public User(string name, int level) { Name = name; Level = level; } public string Name { get; } public int Level { get; } }
Console.WriteLine(new User("Ada", 19).Name);
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

20확장 스타일 동작

C#에서 확장 스타일 동작 개념을 코드로 빠르게 확인하는 객체지향 예제입니다.

C# code

// 확장 스타일 동작
using System;

public record Profile(string Name, string[] Tags);
Console.WriteLine(new Profile("Ada", new[] { "cs" }));
알아두면 좋은 점

객체 예제는 데이터와 동작이 어떻게 묶이는지에 집중하면 이해가 빨라집니다.

자주 하는 실수

객체 하나에 너무 많은 책임을 넣으면 구조가 빠르게 무거워집니다.

정리하며

  • 타입을 고를 때는 상속 구조보다 정체성 비교인지 값 비교인지를 먼저 정합니다
  • record의 with는 얕은 복사라 내부 컬렉션은 원본과 계속 공유됩니다
  • 확장 메서드는 정적 호출이라 null 인스턴스에서도 호출 자체는 성공합니다
  • 생성자 인자가 늘어나면 기본값 남발 대신 빌더나 설정 객체로 옮겨 담습니다

더 깊이 들어가고 싶다면 C# 학습 라이브러리에서 다른 주제 가이드를 이어서 보거나, 언어 비교에서 같은 개념이 다른 언어에서 어떻게 표현되는지 확인해 보세요.