티스토리 뷰

## 개요

오랜만에 닷넷 및 C# 개발로 돌아왔더니 옛날에 공부했던 내용들이 가물가물해서 프로그램 설계시 주요 키워드들을 다시 정리해보도록 한다. (keywords : compiler에게 알려주기위해 미리정의된(predefined) 예약된(reserved) 식별자(identifiers))

 

## 접근제한자(Access Modifier)

- public : 접근 제한없음

- protected : 파생type까지만 접근 가능

- internal : 현재 어셈블리에서만 접근 가능

- private : 현재 type에서만 접근가능

- protected internal이나 private protected는 개인적으로 잘 안쓰고 가독성도 떨어진다고 생각하기에 패스

 

접근제한자는 되도록 default보다 명시적으로 선언하는것이 좋고, 좁은 범위부터 선언하는것이 안전하다.

일단 private으로 선언하고 외부로 노출이 필요하다고 판단되는 시점에 internal로 변경한다. internal의 경우 동일 어셈블리 내부에서는 public처럼 사용되나 외부 어셈블리에는 private이다. class 접근제한 범위를 어셈블리로 확장해서 이해하면되며 모듈 종속성을 관리하기 좋다. 만약 internal에서 public으로 변경해야하는 시점이 오면 설계에 대해서 한번 더 생각해볼 기회가 생기게된다. 파생클래스 설계 또한 private > (protected internal) > protected > internal > public 순서로 변경이 필요한 시점에 확장한다.

 

## params, in, out, ref

메서드 매개변수의 특징을 선언하기 위한 키워드들

 

### 인수와 매개변수

- 인수(argument) : 함수의 호출부에서 함수로 전달되는 값

- 매개변수(parameter) : 함수의 정의부에서 전달받은 인수를 함수내부로 전달하는데 사용되는 변수

 

### 참조형식과 값형식

- 참조 형식(reference type)

  - class

  - 참조로 전달은 메서드에 변수에 대한 액세스를 전달한다는 의미

- 값 형식(value type)

  - struct

  - 값으로 전달은 메서드에 변수의 복사본을 전달한다는 의미

 

### 키워드별 특징

- params

  - 가변길이 매개변수 선언

  - 매개변수배열은 1차원배열이어야함(e.g. `params int[] list`, `params object[] list`)

  - 일반적인경우는 오버로딩을 사용하고, 길이가 한정되지 않고 type이 같은 매개변수가 필요할 때 사용

- ref

  - 메서드 매개변수가 참조(reference)임을 선언. (인자로 전달전 반드시 초기화 및 할당필요)

  - 값 형식을 참조 형식으로 전달할 때 유용

- in

  - ref와 비슷하나 메서드 매개변수가 read-only임을 선언.

  - 즉, 메서드 내부에서 매개변수 값 수정불가(인자로 전달전 반드시 할당필요)

  - 매개변수 한정자와 제네릭 한정자로 구분됨에 유의(제네릭 한정자로 사용시 반공변(contravariant) 지정)

    - e.g. Action<T> 정의부 : `public delegate void Action<in T>(T obj);`

  - 전달되는 매개변수 복사본을 만들지 않고 큰 객체(e.g. 값형식 구조체)를 참조형식으로 전달하는 경우 유용

- out

  - ref와 비슷하나 메서드 매개변수가 should be write임을 선언.

  - 즉, 메서드에 의해 매개변수의 값이 할당되어야 함을 선언. (메서드 내부에서 매개변수 초기화 및 할당 강제)

  - 매개변수 한정자와 제네릭 한정자로 구분됨에 유의(제네릭 한정자로 사용시 공변(covariant) 지정)

    - e.g. IEnumerable<T> 정의부 : `public interface IEnumerable<out T> : IEnumerable`

    - e.g. Func<T> 정의부 : `public delegate TResult Func<out TResult>();`

  - 메서드가 여러값을 반환하도록 하려는 경우 유용

 

### 공변과 반공변

- References의 링크 참조

 

## abstract와 interface

abstract는 인스턴스화되지 않고 다른 class의 base class로만 사용됨을 나타내는 범위를 수식하는 한정자(modifiers) 키워드이고, interface는 class와 같은 형식(type)을 나타내는 키워드이다. 즉, abstract는 파생될 객체의 특성을 나타내는 기반클래스임을 정의할때 사용하고, interface는 그것을 구현할 class나 struct같은 객체의 행동타입을 정의할때 사용한다.

 

class는 어떤 객체의 속성과 동작집합이고 이런 객체들의 공통된 추상개념 집합을 재사용을 위해 묶을때 abstract를 사용해 base class로 정의한다. 이름 그대로 추상적인 객체이기 때문에 인스턴스화되지 않고 파생클래스를 통해서만 인스턴스화(실체화)된다. 반면에 interface는 어떤 객체가 가져야하는 속성과 동작들에대한 계약집합이라 생각할 수 있다. 상속이 "is a"라면 interface를 통한 구성은 "behaves like"로 표현된다.

 

간단한 예를들면, 

인간, 새, 고래와 같은 동물의 공통된 움직이는 특성을 Animal클래스에 Move()로 정의할 수 있다. 동물은 실체화될 수 없는 추상적인 개념이기 때문에 abstract로 선언한다. 인간은 생각할 수 있고(동물도 하겠지만 일단 넘어가고), 새는 날 수 있고, 돌고래는 잠수할 수 있다. 이는 공통된 특성은 아니므로 각각 IThinkable, IFlyable, IDiveable와 같은 인터페이스로 선언하고 각각에 대해 Think(), Fly(), Dive()와 같은 행동을 정의할 수 있을것이다. 나중에 백인, 흑인, 독수리, 참새, 돌고래, 범고래 등의 객체로 파생되어도 특성과 행동에 맞게 확장이 가능해진다.

 

위는 예시일뿐이고 Move()같은 공통적인 동작은 interface로 노출시키고, Animal의 공통적인 특성만 abstract를 통해 정의하는것이 좋다.

 

보통 OOP에서 Inheritance보다 Composition을 사용한 느슨한 결합을 통한 유연성을 추구하는데 그때문에 abstract보다 interface를 사용해 설계하는 경우가 많다. 상속을 무조건 쓰지 말라는건 아니며 변화가 거의 없을 프로그램 뼈대를 구성하는 특성은 기반클래스를 통한 상속을 활용하고 나머지 변경이 예상되는 부분들은 구성을 적절히 활용하면 된다.

 

## abstract와 virtual

virtual은 메서드, 속성, 인덱서 또는 이벤트 선언을 파생클래스에서 재정의 가능하도록 선언한다. abstract와의 차이점은 abstract는 구현부를 파생클래스에서만 정의 가능하지만, virtual은 선언시점에 정의 가능하다. 말그대로 이해하자면 추상(abstract)은 추상적이고 실체가 없으니 구현부가 없고, 가상(virtual)은 "almost complete"라는 의미를 가지므로 "어느정도는 구현된"이라는 의미라 구현부가 있다. IT쪽이 영어권이 아니어서 한국어로 번역되면서 의미전달이 제대로 안되어서 손해보는 경우가 많다. "어느정도 구현된" 기반클래스의 기능만 사용할지, 재정의된 기능과 같이 사용할지, 재정의된 기능만 사용할지는 파생클래스에서 프로그래밍으로 결정 가능하다.

 

## override와 sealed

sealed는 상속불가를 선언하는 키워드이다.

상속을 계획하지 않는 일반적인 클래스에 선언해주고 상속이 필요해지는 시점에 해제해주면 설계에 대해서 고민도 가능하고 파생설계가 안된 상태에 다른사람이 파생해서 쓰다가 개판나는 경우도 미연에 방지 가능해서 좋다. 개인적으로는 클래스 선언시 항상 internal sealed로 시작한다.

 

반면에 override는 상속된 파생클래스에서 사용되는 키워드이다.

"올라탄다, 우선한다, 덮어쓴다"라는 의미를 가지고 있고, IT에서는 재정의한다라는 의미로 사용된다. (참고로 overload는 초과적재를 뜻하고 동일한 함수(명)이 기대되는것보다 많다는것을 뜻한다) 함수를 재정의하는 오버라이딩 기법은 C#에서는 override키워드를 통해 선언되며 abstract, virtual로 기반클래스에 정의된 메서드나 속성이 파생클래스에서 재정의 되었음을 컴파일러에게 알린다.

 

 

## References

 

- 가물가물한 내 경험

- 책 Effective C# - Bill Wagner

 

https://learn.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/interface

 

interface - C# 참조

'interface' 키워드를 사용하여 구현 형식이 지원해야 하는 계약을 정의합니다. 인터페이스는 관련 없는 형식 집합 간에 일반적인 동작을 만드는 수단을 제공합니다.

learn.microsoft.com

https://ibocon.tistory.com/91

 

[C#] Covariance 공변성 및 Contravariance 반공변성

공변성 및 반공변성 마이크로소프트의 공식문서에서 공변성과 반공변성에 대한 개념을 소개하고는 있지만, 저는 이해하기가 너무 어려웠습니다. 저에게는 글 구성이 너무 난해하고 배경 설명

ibocon.tistory.com

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함