본문 바로가기

C#

[C#] 요점정리

▣ 닷넷이란

-. 모든 것을 포괄하고 있는 이상적인 개발환경

-. 개발에 필요한 개발 언어, 개발 툴, 라이브러리, 기반 기술 등을 제공하는 이상적인 개발환경이다.


▣ 닷넷의 특징

-. 플랫폼 독립성

-. 다양한 언어의 지원

-. 상호 운용성 : 서로 다른 언어끼리의 호환성


▣ C#과 자바 차이

-. 자바는 동적 해석 언어이다

-. 자바는 바이트코드를 인터프리터 방식으로 해석해서 실행한다.

-. C#은 동적 컴파일 언어이다.

-. JIT 컴파일러에 의해서 동적으로 중간언어을 재컴파일해서 실행한다.


▣ 값타입(Value Type)

: 변수를 선언하면 자동으로 메모리가 생성되는 데이터 타입


▣ 선택문

: 프로그램 내에서 주어진 조건에 따라 실행여부를 결정하는 제어문

: if  switch


▣ 추상클래스(abstract)

-. 몸체만 가지고 있을뿐 구현은 파생클래스에서 해줘야함

-. 프로젝트 설계 시 트리구조를 갖는 설계를 하게 될 경우 많이 사용함

-. 추상 메소드 선언시 내포적으로 virtual이 포함되는 관계 


▣ as연산자

: 식을 지정한 데이터형으로 변환


▣ backgroundworker

: 어떤 작업이 오래 걸리는 경우 사용자에게 현재 진행률을 보여줘야하는 경우가 있을때 사용


▣ Boxing과 UnBoxing

-. Boxing: 값타입을 참조타입으로 변환하는 기법

-. UnBoxing: 참조타입을 값타입으로 변환하는 기법


▣ 반복문

: 특정 조건이 만족할 때까지 계속해서 반복하는 제어문

: for, while


▣ 분기문

: 조건문이나 반복문 등에서 특정한 지점으로 제어권을 이동시키는 분기 명령문

: break, continue


▣ 클래스란?

: 클래스는 새로운 데이터 타입을 만드는 데이터 타입 생성기이다.


▣ 접근제어란?

-. 메모리를 보유한 객체를 이용해서 멤버에 점(.)찍고 접근할 수 있는지 없는지의 제어를 말한다.


-. public: 멤버에 직접 접근할 수 있다.

-. private: 멤버에 직접 접근할 수 없다.


▣ private에 접근하는 방법

-. public 멤버 함수의 매개변수를 통해서, 리턴을 통해서 접근

-. 이 때 매개변수와 리턴값이 할당되는 원리는 값복사의 기법을 이용한다..


▣ private 멤버 함수를 왜 사용할까?

: 해당 클래스 내부에서만 사용 가능하다.


▣ private 멤버 필드를 사용하는 이유?

-. 자료를 보호하기 위해서

-. 내부적으로만 사용하기 위해서


▣ 속성

-. private 멤버 필드에 값을 할당하고 얻어내기 위해 사용

-. Set과 Get 형식의 함수를 일반화한 형태


▣ 속성의 특징

-. 외부적인 사용은 public 멤버 변수처럼 사용되지만 내부적으로는 함수의 방식으로 동작한다.


▣ 속성을 사용하는 이유

-. 속성을 사용하는 이유는 직관적이며 편리하게 값을 변경하기 위해서이다.


▣ 값타입의 변수와 참조타입(클래스) 변수에 대한 특징

-. 값타입은 변수의 이름을 선언함과 동시에 메모리가 할당

-. 클래스는 변수의 선언과 변수에 대한 메모리 할당이 분리되어 있다. 객체 변수 선언만 하면 메모리 없고 메모리 생성, 인스턴스 생성하는 순간 메모리 있는 상태가 된다.


▣ 참조타입의 선언과 메모리 할당

: 참조타입의 변수를 선언할 때 new를 하지 않으면 메모리가 생성되지 않는다. 하지만 참조타입의 변수 선언 자체는 참조값 자체를 담을 메모리를 의미한다. 즉 4바이트의 정수형 참조값을 담을 수 있는 메모리를 생성하고 객체 자체의 메모리는 아직 힙에 생성하지 않는다는 의미이다.


결론적으로 참조타입의 변수만 선언한다면 참조값을 담을 메모리가 생성된다. 하지만 참조값 자체는 null이며 new를 하는 순간 힙에 객체의 메모리가 할당된다.


▣ 값타입과 참조타입의 구분하는 방법

-. 값타입과 참조타입의 메모리를 가리키는 방식

-. 값타입과 참조타입의 값복사

-. 값타입과 참조타입의 메모리 생성


▣ 값타입과 참조타입의 메모리를 가리키는 방식

-. 값타입: 메모리를 직접 가르킨다.

-. 참조타입: 메모리를 참조를 통해서 가르킨다.


▣ 값타입과 참조타입의 값복사

-. 값타입: 값타입끼리 할당할 때 메모리의 값들을 그대로 복사

-. 참조타입: 참조타입끼리 할당할 때 참조값만을 복사


▣ 값타입과 참조타입의 메모리 생성

-. 값타입: 변수의 선언과 동시에 메모리 생성

-. 참조타입: 변수의 선언과 메모리 생성 분리



▣ 스택과 힙에 대해 말한다 

스택이란 처리해야할 요청을 저장하는 데이터 저장소 또는 버퍼이다. 


힙은 프로그램이 실행될 때까지는 알 수 없는 가변적인 량만큼의 데이터를 저장하기 위해 

프로그램의 프로세스가 사용할 수 있도록 미리 예약되어 있는 메인 메모리의 영역이다.

예를 들면 하나의 프로그램은 처리를 위해 한 명이상의 사용자로부터 서로 다른 양의 입력을 받을 수 있으며

즉시 모든 입력데이터에 대해 처리를 개시한다. 

운영체계로부터 이미 확보된 일정량의 힙 저장공간을 가지고 있으면 저장과 관련된 처리를 좀 더 쉽게 할 수 있으며

일반적으로 필요할 때마다 운영체계의 운영체계에게 매번 저장공간을 요청하는 것보다 빠르다. 

프로세스는 필요할 때 heap 블록을 요구하고 더 이상 필요 없을 때 반환하며 

이따금씩 자투리모으기를 수행함으로써 자신에게 할당된 heap을 관리한다.

여기서 자투리모으기란 더 이상 사용되지 않는 블록들을 사용 가능한 상태로 만들고

또한 heap 내의 사용 가능한 공간을 인지함으로써 사용되지 않은 작은 조각들이 낭비되지 않도록 하는 것을 말한다.


힙은 이 용어는 분명히 다른 용어인 스택(stack)의 영향을 받았다. 

스택은 블록들이 저장공간으로부터 어떤 순서에 입각하여 꺼내어지고 또 같은 방법으로 반환된다는 것을 제외하고는 heap과 비슷하다.

 

▣ 값타입과 참조타입의 메모리 형성의 차이  


값타입과 참조타입은 메모리가 생성되는 부분이 다르다.

일반적으로 값타입(Value Type)은 스택(Stack)에 메모리가 생성되며

그리고 참조타입(Reference Type)은 힙(Heap)에 메모리가 생성된다고 생각한다.

하지만 참조타입은 스택과 힙영역을 동시에 사용하게 된다


값타입과 참조타입은 참조타입의 경우 참조값은 스택에 실제의 메모리는 힙영역에 생성하는 되는 것이다.

우리가 특정 클래스를 이용하여 객체의 이름만 만들었다면 스택에 4바이트의 참조값을 위한 공간이 확보되는 것이다.

그리고 new 연산자로 객체의 메모리를 생성하였다면 그때에 힙영역에 해당 객체의 메모리가 생성되는 것이다. 

이에 반해 값타입은 변수이름의 선언과 동시에 스택영역에 메모리를 확보하게 된다


▣ 클래스와 구조체의 차이

-. 구조체는 값타입이며 클래스는 참조타입이다.


▣ 구조체를 사용하는 이유

-. 구조체는 직접적으로 메모리에 접근하기 때문에 참조의 낭비를 막을 수 있다.


▣ 구조체의 특징

-. 구조체는 상속할 수 없으며 또한 상속해 줄 수도 없다.


▣ Stact 메모리 영역

-. 프로그램을 실행하는데 필요한 메모리 공간

-. 함수 내에서 선언된 변수는 무조건 스택에 만들어진다.


▣ 힙의 메모리

-. new를 이용해서 만든 메모리는 무조건 힙에 만들어진다.


▣ ref와 out키워드

-. ref: 참조할 변수는 반드시 초기화되어 있어야 한다.

-. out: 참조할 변수가 반드시 초기화할 필요는 없다.


-. ref: 함수 외부에서 함수 내부로 값을 전달할 때 사용하는 참조 키워드

-. out: 함수 내부에서 함수 외부로 값을 추출할 때 사용하는 참조 키워


▣ out키워들 사용하는 경우

: 함수로부터 값을 얻어낼 때 주로 사용한다.

  -. 그렇기 때문에 초기화를 할 필요가 없는 것이다


▣ ref에 의한 참조(Reference)

: 참조형 매개변수는 "메모리의 위치에 대한 참조"이다. 위에서 함수를 호출하면 참조형 매개변수는 변수의 메모리 주소에 대한 참조를 가지게 된다.


▣ Const 상수

-. 상수를 선언하는 키워드


▣ 어셈블리

: 컴파일한 결과파일(중간언어 형태로 되어 있음)


▣ 네임스페이스

: 어셈블리 내에서 각각의 클래스들을 구분하는 기준이 네임스페이스이다.


▣ static 키워드

: 모든 클래스에서 공유하기 위한 멤버를 선언하기 위해 사용한다.


▣ static 문제점

: 스태틱을 사용할 대 가장 큰 문제점으로 대두되는 것은 여러 곳에서 동시에 데이터를 사용할 때 동기화의 문제이다.

그럴 때 필요한게 쓰레드 이다.


▣ 스택의 메모리

-. 함수 내에서 선언된 변수는 무조건 스택에 만들어진다


▣ 힙의 메모리

-. new를 이용해서 만든 메모리는 무조건 힙에 만들어진다.


▣ 스택과 힙의 조화

-. 프로그램에서 사용되는 메모리는 스택과 힙의 조화로 이루어진다.


▣ 스태틱 생성자

-. 스태틱 생성자는 스태틱 멤버 필드의 메모리가 생성된 직후 호출되는 스태틱 전용의 생성자 함수이다.


▣ 스태틱 생성자의 특징

-. 접근제어를 사용할 수 없음

-. 매개변수를 가질 수 없음


▣ 스레드란?

-. 하나의 프로그램 내에서 실행되는 함수

-. 한순간에 두 개의 함수가 동시에 실행되면 두 개의 스레드가 동작하는 것이다.


▣ 스레드 프로그램을 할 때 주의해야 할 사항

-. 우선권(Priority)

-. 동기화(synchonization)


□ this란

-. 자기 자신을 참조하는 가상의 참조 변수


▣ 참조타입과 값타입 차이

-. value type : 파라메터를 복사해서 보내줍니다. 스택에. 원본의 변경이 없습니다. 통째로 복사하니 스택도 무리가 가고, 속도도 느립니다.

-. reference type : 포인터만 넘겨줍니다. 스택에 무리도 없고, 빠릅니다. 원본을 변경할때 편하지만 잘못하면 원본을 변경 시킬 수 있습니다. 포인터를 넘겨주는것을 컴파일러가 다시 프로그래머가 일기 쉽도록 참조 형식으로 변환하는겁니다. 기계어로 바꾸면 포인터가 넘어간다는 사실


▣ unsafe 코드

-. C#에서 포인터를 사용하면 unsafe 코드가 된다.

-. CLR이 메모리를 전자동으로 관리해주는데 사용자가 직접 메모리를 건드리는것은 안전하지 못하기 때문에 unsafe 코드라고 한다.


▣ fixed 키워드

-. CLR에 의해서 해당 메모리의 포인터를 이동시키지 못하도록 하는 키워드.


▣ 다형성(Polymorphism)

-. 하나로 여러 가지 일을 하는 


□ 다형성이 적용되는 곳

-. 업캐스팅(Upcasting)

-. 오버라이딩(Overriding)

-. 가상함수(Virtual Function)

-. 상속(Inheritance)

: 추상 클래스

: 인터페이스


▣ 멤버 변수의 경우

-. 일반적인 경우 멤버 변수는 무조건 private으로 선언하는것이 맞다


▣ 언제 public 멤버를 사용하는가?

-. 클래스를 다른 사람에게 만들어준다고 가정

-. 다른 사람이 사용할 함수는 전부 public, 그외에는 전부 private


▣ 상속(Inheritance)

-. 상속(Inheritance)이란 만들어둔 클래스를 다시 사용할 수 있는 방법을 말한다.


▣ 생성자(Construcrot)

생성자는 객체 지향 프로그래밍에서 객체의 초기화를 담당하는 서브루틴을 가리킨다. 생성자는 객체가 처음 생성될때 호출되어 멤버 변수를 초기화하고, 필요에 따라 자원을 할당하기도 한다. 객체의 생성 시에 호출되기 때문에 생성자라는 이름이 붙는다.


▣ UnBoxing의 순서

-. 해당 객체가 지정한 값타입을 Boxing한 값인지 확인

-. Boxing된 객체라면 객체의 값을 값타입 변수에 복사한다.

-. Boxing한 메모리와 UnBoxing한 메모리 두 개가 존재한다.


▣ 인터페이스(Interface)란?

-. 클래스 내의 구성요소들의 구현부가 없고 선언부의 집합으로만 이루어져 있는 클래스이다.

-. 내부의 멤버가 몽땅 추상으로 이루어져 있는 클래스

-. 인터페이스는 계약(Contract)를 위해서 사용하는 클래스의 한 종류이다.

-. 다수의 많은 사람들이 모여서 프로그램을 할 때에는 반드시 필요하다.

-. I로 시작하고 class 대신 interface로 선언

-. 구현을 가질수 없지만, 다중 상속이 가능하다

-. 인터페이스를 상속 받는 클래스는 반드시, 인터페이스의 멤버를 구현해야한다

-. 제한자 선언을 하지 않아도 모두 public

-. 인스턴스를 만들 수 업속, 상속받은 클래스 형태로만 인스턴스화 가능(다형성)

-. 클래스와 선언하는 방법은 비슷하지만 안에 있는 멤버로 필드를 가질수 없다. 필드 이외에 메소드, 이벤트, 인덱서, 프로퍼티만을 가질 수 있다

-. 접근 제한자를 쓸 수 없으며 모든 것이 public로 자동으로 선언이 된다. 또한 인스턴스도 만들 수가 없다

-. 인스턴스를 만들 수 는 없지만 인터페이스를 상속받는 클래스의 인스턴스를 만드는 것은 가능하다. 단 자식 클래스는 인터페이스에 선언되어 있는 모든 메소드 및 프로퍼티를 구현해 주어야 하며, public으로 수식해야 한.


▣ 추상클래스

-. 추상 클래스는 미완성 클래스를 말한다

-. 하나 이상의 순수 가상 함수를 가지는 클래스

-. class 앞에 abstract를 추가, 함수의 경우는 반환형 앞에 abstract를 추가함

-. 함수의 경우 virtual 선언 할 필요 없음(무조건 구현해야함, 상속받은 클래스에서는 override 선언)

-. 추상클래스는 인터페이스와는 달리 메소드의 구현이 가능하다. 그러나 클래스와는 달리 인스턴스를 가질 수는 없다

-. 일반 클래스와 동일하게 추상클래스 역시 따로 접근 제한자를 명시하지 않으면 private로 선언된다

-. 추상클래스 안에는 abstract키워드를 이용해서 추상 메소드를 선언하는 것도 가능하다

-. 몸체 없는 함수를 하나라도 포함하고 있는 클래스

-. 몸체 없는 함수를 포함하고 있지 않더라도 클래스를 선언할 때 abstract 키워드를 포함하고 있는 경우

-. 추상 클래스는 객체(인스턴스)를 생성할 수 없다.

-. 추상 함수는 자동으로 가상함수가 된다.

-. 추상 함수는 virtual 키워드를 사용하지 않지만 자동으로 virtual이 된다.


▣ 추상클래스와 인터페이스

-. 단일 상속과 다중 상속의 차이 인터페이스는 다중 상속이 가능하다 

-. 직접적으로 초기화 할 수 없다

-. 인터페이스는 모든 인자와 메소드들이 구현부만 있어야 하지만, 추상클래스는 구현된 메소드를 일부 포함해도 상관없다

-. 다만 클래스의 멤버중에 abstract멤버가 한개라도 존재하면 그 클래스는 abstract이다

-. abstract class는 생성자를 가질수 있다. 그러나 interface는 그럴수 없다. 

-. abstract class는 abstract가 아닌 매소드를 가질수 있다. 그러나 interface는 그럴수 없다. 

-. abstract class는 맴버 변수를 가질 수 있다 .그러나 interface는 그럴수 없다. 

-. abstract class는 매소드의 접근자 모두를 가질수 있다. public, private, internal.. ect 그러나 iterface 는 public만 가질수 있다. 

-. abstract class는 클래스 이므로 하나만 상속이 가능하나. interface는 다중 상속이 가능하다


▣ 추상클래스의 추상 메서드

-. 추상클래스는 추상 메서드를 한개 이상 포함하고 있다

-. 추상화 메서드는 메서드의 원형만 정의된 독특한 메서드로 abstract 키워드 사용

-. 추상클래스 내에서만 선언할 수 잇다

-. 추상화 클래스는 직접 사용할 수 없으며, 반드시 다른 클래스에서 상속되어 추상 메서드를 오버라이딩 해야 사용가능


▣ virtual 키워드와 가상 메서드

-. 가상 메서드는 일반 클래스에서 선언되어 사용된다

-. 가상 메서드는 virtual키워드를 사용해 선언하며, virtual 키워드를 붙인다는 것을 빼면 일반 메서드와 동일

-. 가상메서드는 일반 메서드와 동일하게 메서드 원형뿐만 아니라 구현도 선언과 동시에 한다


▣ 제네릭(Generic)이란?

-. 클래스에 사용할 타입을 디자인시에 지정하는 것이 아니라 클래스를 사용할 때 지정한 후 사용하는 기술을 말한다.


▣ 지역변수와 멤버변수의 차이

-. 지역변수

 : 자동으로 초기화가 되지 않는다

 : 블록안에서 선언된 변수

 : 사용범위 : 블록안에서만 사용가능 

 : 매개변수도 지역변수가 된다.

 : 메서드안에서 지역변수 이름과 멤버 변수 이름이 동일하다면 지역변수가 사용된다.


-. 멤버변수

 : 자동으로 초기화가 이루어진다. (객체는 null)

 : 클래스내에서 모두 사용 가능


▣ 이벤트와 델리게이트 차이

-. 이벤트는 public 한정자로 선언되어 있어도 자신이 선언되어 있는 클래스 외부에서는 호출이 불가능합니다. 반면 델리게이트는 public이나 internal로 수식되어 있으면 클래스 외부에서도 얼마든진 호출이 가능하지요.

-. 이벤트와 델리게이트는 비슷하다 단지 차이점은 속성이 생긴 이유와 비슷하다. 데이터 접근을 한 단계를 더 추가하여 캡슐화를 강화한다는 것에 있다


▣ 이벤트와 델리게이트 사용용도

델리게이트는 델리게이트대로 콜백 용도로 사용하고, 이벤트는 이벤트대로 객체의 상태 변화나 사건의 발생을 알리는 용도로 따로따로 사용해야 합니다.


▣ 델리게이트

메서드들에 대한 참조를 가질 수 있는 하나의 사용자 정의 타입이다


델리게이트는 메서드를 대신해 호출을 받아서 우리가 원하는 메서드를 대신해 호출한다. 대리인 역할이라고 하면 될듯하다. C++의 함수 포인터와 비슷한 개념인데, 함수 포인터는 실제론 함수의 메모리 주소만을 가지고 있는 것이기 때문에 매개변수, 리턴값등을 미리 검사할 수 없어 오류를 발생하기 쉽다. 이에 비해 델리게이트는 완전히 객체 지향적이고 타입 안정성을 갖추었다

-. 델리게이트는 메소드를 가리키는 참조형으로서 메소드의 번지를 저장하거나 다른 메소드의 인수로 메소드 자체를 전달하고 싶을 때 사용


▣ 이벤트

-. 이벤트는 객체의 상태변화나 사건의 발생을 알리는 용도로 사용


▣ 델리게이트 사용 이유

저는 델리게이트를 주로 2가지로 사용합니다.

같은 자료형을 다른 클레스에서 호출할때 주로 사용합니다.

이 방법이 이벤트 처리 할때 델리게이트를 사용하여 이벤트를 발생시킵니다.

다른 하나는 바로 질문자님이 질문 하신 부분입니다.

쓰레드를 사용 할때 UI 화면에 무엇인가 출력 할때 발생하는 크로스 쓰레드를 해결하기 위하여 사용합니다.

예를 들어 textBox1 에 "TEST" 라는 글자를 출력 할때 쓰레드가 아닌 일반 클레스에서는 호출이 되죠

그러나 쓰레드 안에서 출력 할려고 하면 크로스쓰레드가 걸리게 됩니다.

이때 델리게이트를 이용하여 크로스쓰레드를 해결합니다.

델리게이트를 사용 여부 쯕, 크로스쓰레드가 발생했는지 여부를 확인 하는것이 Invoke 가 되는것이구요

다시 말해 textBox1.Invoke 를 했을때 true 가 나오면 델리게이트를 사용하여 다시 함수를 호출 하면

크로스쓰레드가 해결되는 것이지요

질문자님께서 질문하신 내용에 대한 답변은

델리게이트는 크로스쓰레드가 발생하는 출력을 정상적으로 출력하기위하여 대리자를 사용 하는 것이고,

Invoke를 쓰는 이유는 크로스쓰레드가 발생했는지 확인하기 위함입니다.

델리게이트를 쓰지 않으면 크로스쓰레드가 발생한다는 것이 문제점이구요


-. 위임인데 의미 그대로 메소드의 역할을 위임하는 것이라고 할 수 있다. 변수의 경우, 각 변수가 가지고 잇는 값들을 어떤 특정한 패턴, 함수에 의해 변형되어, 개발자의 의도대로 결과 값을 얻을 수가 있다. 이런 특징적인 역할을 하는 함수들을 특정한 조건이나. 의도를 가지고 묶음으로 만들어내 좀 더 간편하게 사용하도록 하는것이 목적이며, UI같은 복잡한 객체를 상속하는 것을 피하고, 메소드를 재정의 하지 않음으로써 좀 더 객체 지향적인 프로그래밍을 할 수 있도록 도와준다


▣ 가비지 컬렉터

-. C#에서는 new는 사용하지만 메모리를 제거하기 위한 delete는 사용하지 않는다. 가비지 콜렉터를 지원해주기 때문이다.

가비지 콜렉터는 CLR 내에서 동작하면서 메모리의 청소가 필요하다고 생각될 때 시스템에 의해서 구동되는 메모리 청소부와 같은 역할을 한다.

-. 결국 new를 이용해서 생성한 모든 객체의 메모리는 힙영역에 만들어지며 가비지 콜렉터의 관리 대상이 되는 것이다.

-. 힙에 생성되는 객체의 메모리

-. C#의 메모리 관리자 역할을 담당한다


▣ readonly 상수

-. 반드시 초기화할 필요 없다.

-. 생성자에서 딱 한 번 값을 할당할 수 있다.



▣ 오버로딩

-. 하나의 이름으로 여러 개의 함수를 만드는 기법


▣ 상속(Inheritance)

-. 상속이란 만들어둔 클래스를 다시 사용할 수 있는 방법을 말한다.


▣ sealed 키워드

-. 상속을 금지시키는 키워드


▣ 생성자

-. 객체의 메모리 생성된 직후에 호출되는 함수


▣ 소멸자

-. 객체의 메모리가 제거될 때 호출되는 함수


▣ protected 접근 제한자

-. 객체의 이름으로 점(.) 찍고 접근할 때에는 private이면서, 상속관계에서만 완벽한 public으로 행동한다.


▣ internal 접근자

-. 하나의 Assembly 내에서만 접근을 허락하는 접근자

-. 같은 어셈블리 안에 있어야 접근이 가능하다.


▣ protected internal

-. 어셈블리가 다르더라도 상속을 받은 하위 클래스에서 상위 클래스의 internal에 접근 가능하게 하기 위헤서 protected internal을 제공한다.


▣ 오버라이딩

-. 부모의 함수를 자식이 다시 만드는 행위를 오버라이딩이라고 한다.

-. 자식은 new 키워드를 사용해서 함수를 재정의해야 한다.


▣ base 키워드

-. base 키워드는 디자인 타임에 상위 클래스를 참조할 수 있는 유일한 참조 변수이다.

-. 생성자 내에서 부모 생성자를 호출하기 위해 사용한다.


▣ 추상 클래스의 특징

-. 추상 클래스는 객체를 생성할 수 없다

-. 추상 함수는 자동으로 가상함수가 된다.

-. 추상 함수는 virtual 키워드를 사용하지 않지만 자동으로 virtual이 된다.


▣ 다중 상속의 장점

-. 여러 개의 클래스를 동시에 상속받아 하나의 클래스로 많은 작업을 할 수 있다.


▣ 업캐스팅

-. 하위 클래스형의 객체가 상위의 클래스형으로 캐스팅되는 것을 말한다.


▣ 업캐스팅의 장점

-. 하나의 매개변수의 형으로 여러 형을 받아줄 수 있다는 장점이 있다.

-. Animal형으로 Animal을 상속받은 Dog와 Cat을 받아줄 수 있다.


▣ String과 StringBuild 차이점에 대해서 설명해주세요.

-. String 클래스는 변경이 불가능한 immutable 클래스이고, StringBuil 클래스는 변경이 가능한 mutable 클래스이다.


예제)

string str = "안녕";


"안녕"이라는 문자열을 메모리에 생성하면, str은 "안녕"이라는 문자열 객체를 가리키는 레퍼런스를 담고 있는 것이다.

우린 흔히 string 문자열에 += 로 문자열을 더 추가 시킨다.



str += "하세요";


그럼 이 때 string은 불변객체 인데도 불구하고 바뀐다. 왜냐


str += "하세요" 라는 문장은 내부적으로


str = new StringBuilder("안녕").append("하세요").Tostring();


으로 변하게 된다. String 객체 자체는 불변이기 때문에 내용을 바꿀 방법이 없다.



▣ uisng 이라는 키워드는 네임스페이스를 링크하기 위해서 사용하기도 하지만 객체를 생성할 때 또한 사용되기도 합니다.

이때 using을 이용하는 목적에 대해서 설명해주세요.

-. 일반적으로 객체를 생성할 경우 메모리에 데이터가 올라가고 메모리 자원관리를 위해 객체 사용이 끝난 다음에 Dispose()를 해주어야 합니다. using문을 사용해서 객체를 사용하면 using문의 {}를 벗어나면 객체에 관련된 자원(혹은 객체에서 사용한 자원)이 자동으로 해제되며 예외 발생 시에도 자원을 해제해줍니다.


*참고 : IDisposeable 인터페이스를 구현한 객체만 using문을 사용할 수 있습니다.




▣ C# 2.0에서는 델리게이틀 쉽게 등록하는 문법적 편의를 위해서 익명 메서드라는 문법을 제공했습니다. 그리고 C# 3.0에는 이 익명 메서드를  더 쉽게 사용할 수 있게 하기 위해서 람다식이라는 문법이 등장하게 됩니다. 그렇다면 익명메서드와 람다시 구문을 사용하는 코드를 작성해주세요. 


-. 람다식 = 식과 문을 포함하고 대리자나 식 트리 형식을 만드는데 사용할 수 있는 익명 함수 익명 메서드 혹은 무명 메서드 = 사용자의 입력에 따라서 method가 갖는 함수가 달라집니다. 그런데 그 함수가 클래스 상에 존자하는 함수는 아닙니다. 하나의 메서드 안에 delegate(int a, int b)로 시작해서 중괄호 안에 마치 또 하나의 함수처럼 코드블록을 가진것이 무명 메서드입니다.



▣ 닷넷에서 데이터 타입은 값 타입과 참조 타입으로 구분되어 힙영역과 스택영역에 데이터를 나누어서 저장하게 됩니다. 때문에 빈번하게 박싱/언박싱이 일어나게 됩니다. 그렇다면 박싱 언박싱은 무엇인지 그리고 성능에 있어서 어떠 영향을 미치는지 설명해주세요.


-. 박싱: 스택에 있는 데이터가 힙으로 복사(묵시적 & 명시적)

int = 123; 


object ob = i; //박싱(묵시적 변환)


-. 언박싱: 힙에 있는 데이터가 스택으로 복사(명시적)

int = 123;


object ob = i;


int j = (int)ob; // 언박싱(명시적 변환)


-. 성능에 미치는 영향

: 박싱 및 언박싱 과정에는 많은 처리 작업이 필요합니다. 값 형식을 박싱하는 경우 완전히 새로운 객체를 할당하고 구성해야 하며, 이러한 작업에는 할당 작업보다 최대 20배의 시간이 걸립니다. 언박싱에 필요한 캐스팅도 상당한 계산 과정이 필요한데, 할당 작업보다 4배의 시간이 걸릴 수 있습니다. 하지만 사용상의 편의성 때문에 사용하게 됩니다.


*참고

stack

-. 자동 변수들이 저장되는 곳(지역변수)

-. LIFO(Last in First Out) = 나중에 들어간게 먼저 나온다


Heap

-. 동적 메모리 할당할 경우 Heap영역에 할당 (인스턴스 변수 = 클래스내에 선언되는 변수)

-. FIFO(First In First Out) = 먼저 들어간게 먼저 나온다.




▣ 객체를 만들 때 메모리 해제를 위해서 일반적으로 IDisposable 인터페이스를 상속받아서 처리하게 되는 경우가 많습니다. 닷넷에서 소멸자는 Dispose(), Finalize()가 존재하는데 이 두 가지의 차이점은 무엇인지 기술해주세요.


-. Dispose는 더 이상 객체 사용이 불필요한 경우 명시적 제어

-. Finalize는 프로그래머가 Dispose 호출에 실패하는 경우 누수되지 않도록 백업 기능 제공


-. 실행순서: Close -> Dispose -> Finalize


GC.SuppressFinalize => Disopose가 호출될 경우 더 이상 Finalize가 호출될 이유가 없기 때문에 호출을 명시적으로 막는다


일단 실행 순서를 보면 Close -> Dispose -> Final입니다.

 


Close 단계에서는 해당 객체가 제공하는 서비스를 닫아줄 것을 요청하는 부분인데, 대부분 Dispose와 직접 연결됩니다. 즉, 사실상의 사용 중단을 통보하는 것입니다. 다만 Windows Forms의 경우 창을 정말로 닫을 것인지를 이벤트에 의하여 판정하는 부분이 있는데 여기서 허용하지 않을 경우 Dispose가 호출되지 않습니다.


그리고 Dispose가 하는 일은, 소멸자가 언제 불릴지 알 수 없는 상황에서 좀 더 정확하고 빠르게 비 관리 영역 상에 존재하거나 데이터의 크기가 큰 메모리 블럭을 사전 해지할 필요가 있을 경우 명시적으로 이를 해지시켜주기 위한 목적으로 존재합니다. 주로 IDisposable 인터페이스를 구현함으로서 이를 만족시키며 C#의 using 구문과 호환됩니다.


마지막으로 Finalize는 가비지 컬렉터에 의하여 "언제인지 알 수 없지만 언젠가는 꼭 불리는" 소멸자입니다. C#에서는 문법의 특색을 살리고 C/C++ 프로그래머들의 관점을 배려하기 위하여 VB.NET에서처럼 Finalize 메서드를 정의하지 않고 소멸자 모양을 그대로 유지한 것입니다. 소멸자의 경우, 간혹 Dispose 메서드를 호출하지 않은 채로 다다라서 소멸자가 먼저 불릴 경우가 있습니다. 이런 경우를 대비하기 위해서 소멸자는 보통 아래와 같이 구성됩니다.


try { ((IDisposable)this).Dispose(); }


catch { }


GC.SupressFinalize(this);


소멸자에서 Dispose 메서드를 불러 남아있을지 모르는 비관리 영역의 리소스를 해지하여 메모리 누수를 완전히 예방하고 최종적으로는 소멸자가 다시 불리지 않도록 가비지 컬렉터에 소멸자가 제 역할을 온전히 수행하였음을 통지하는 것으로 소멸자의 역할이 완료됩니다.



* Finalize 메서드 사용 지침

: 기본 클래스의 Finalize 메서드는 C# 및 C++ 소멸자 구문을 사용하여 자동으로 호출된다. 종료가 필요한 개체에 대해서만 Finalize를 구현. Finalize메서드를 구현하면 성능이 저하될 수 있습니다. Finalize 메서드가 필요하면 클래스 사용자가 Finalize 메서드를 호출할 필요가 없도록 IDisposable을 구현할 것인지 고려 Finalize 메서드를 보다가 가시적인 메서드로 만들지 않습니다. 이 메서드는 protected여야 합니다.

'C#' 카테고리의 다른 글

[C#] DB Connection Keep or Close  (0) 2018.07.25
[C#] DB Connection Pooling  (0) 2018.07.25
[C#] 배열 복사  (0) 2018.07.16
[C#] Thread(스레드)  (0) 2018.07.16
[C#] Naming 규칙  (0) 2018.07.16