1. Class
클래스는 객체지향언어에서 객체(object)의 틀을 정의하는 방법이다. 객체는 속성과 행동으로 이루어져 있으며, 객체의 틀을 정의하고 이를 실체화한 것을 객체 또는 인스턴스(Instance)라고 한다.
C#에서 객체의 틀은 class
예약어로 정의하며, new
연산자로 메모리를 할당하여 객체의 틀을 실체화하여 사용한다.
속성은 필드(Field), 행위는 메서드(Method)로 부른다.
- 인스턴스 멤버 : 실체화된 객체의 멤버(필드, 메서드)
- 정적(static) 필드/메서드 : 실체화된 객체의 전역 멤버(필드, 메서드)
- 정적(static) 생성자 : 객체가 실체화되는 시점에 단 한번만 불리는 생성자, 주로 정적 필드 초기화에 사용
class Book
{
public string Title;
public decimal ISBN13;
public void Open()
{
Console.WriteLine("Book is opened");
}
public void Close()
{
Console.WriteLine("Book is closed");
}
}
2. Interface
객체지향언어에서는 클래스(또는 모듈)에 응집도(Cohesion)를 높이고 서로 간에 결합도(Coupling)을 낮추는 것이 원칙이다.
실제 구현에서는 클래스 상속을 최소화하거나 배제하고, 추상 클래스나 인터페이스를 사용하여 결합도를 줄이도록 권장하고 있다.
C#에서는 클래스 다중상속이 불가능하므로 interface
예약어를 이용하여 다중상속을 지원하고 있다.
인터페이스의 특징은 다음과 같다.
- 인터페이스 내에서는 메서드, 이벤트, 인덱서, 프로퍼티를 사용할 수 있다.
- 인터페이스는 필드를 포함할 수 없다.
- 모든 멤버는 public 접근 제한자를 기본으로 지정한다.
- 몸체가 정의되지 않는 추상 메서드를 멤버로 가진다.
- 인터페이스는 다른 인터페이스를 상속 가능하다.
- 클래스는 인터페이스 다중 상속할 수 있다.
// 추상클래스
abstract class DrawingObject
{
public abstract void Draw();
public abstract void Move(int offset);
}
// 인터페이스
interface IDrawingObject
{
void Draw();
void Move(int offset);
}
3. Inheritance
객체지향언어에서 상속(Inheritance)은 공통적인 특징을 정의한 클래스의 기능을 물려받는 방법이다.
상속하는 클래스는 부모(parent), 기반(base), 슈퍼(super) 클래스로 불리고, 상속을 받는 클래스는 자식(child), 파생(derived), 서브(sub) 클래스로 불린다.
상속받은 클래스는 부모의 속성과 행위를 접근 제한자(Access Modifier) 규칙에 따라 접근(Access)할 수 있다.
C#은 단일 상속(Single inheritance)만 지원하며, 둘 이상의 부모 클래스로부터 다중 상속(Multiple inheritance)을 허용하지 않는다.
상속 관계에 있는 클래스 간에 부모 클래스는 자식 클래스로 형변환이 가능하지만, 자식 클래스는 부모 클래스로 형변환을 할 수 없다.
public class Computer
{
bool powerOn;
public void Boot() { }
}
public class Notebook : Computer
{
bool fingerScan;
public bool HasFingerScanDevice() { }
}
public class Desktop : Computer
{
}
C#의 모든 형식(Type)은 object 클래스를 상속받았으며, 값 형식(Value type)과 참조 형식(Reference type)의 구분을 위해 값 형식을 가지는 모든 형식은 *object*의 자식 클래스인 *System.ValueType*을 상속받아 생성된다.
C#의 최상위 클래스인 object는 4가지 메서드를 포함하고 있다.
public class Object
{
public virtual bool Equals(object obj); // 값을 비교한 결과를 boolean 값으로 반환
public virtual int GetHashCode(); // 인스턴스를 고유하게 식별할 수 있는 4바이트 int 값을 반환
public Type GetType(); // 해당 인스턴스의 타입 정보를 반환
public virtual string ToString(); // 해당 인스턴스가 속한 클래스의 전체 이름을 반환
}
-
sealed
: 상속을 받지 못하도록 제한하는 예약어 -
as
: 형변환이 가능하다면 인스턴스 값을 반환하고, 불가능하면 null을 반환하는 예약어 -
is
: 형변환 가능성 여부를 boolean 값으로 반환하는 예약어 -
typeof
: 클래스 이름으로부터 type을 반환하는 예약어 -
this
: 클래스 내부 코드에서 객체 자신을 가리키는 예약어 -
base
: 클래스 내부 코드에서 부모 클래스를 가리키는 예약어
4. Polymorphism
객체지향언어에서 다형성(Polymorphism)은 하나의 메소드나 클래스를 다양한 방법으로 동작시키는 것을 의미한다.
C#에서는 다형성의 구현을 메서드 오버라이드(Override)와 오버로드(Overload)를 통해 제공한다.
메서드 오버라이드는 상속관계에 있는 클래스 간에 자식클래스가 부모클래스의 메서드를 재정의(Override) 함으로써 각각의 객체가 다른동작을 가능하도록 하는 것이다.
자식클래스에서 재정의 할 메서드를 부모클래스에서 virtual
예약어를 사용하여 정의하고,
자식클래스는 override
예약어를 사용하여 정의한다.
class Mammal
{
virtual public void Move();
}
class Lion : Mammal
{
override public void Move();
}
-
virtual
/override
: 메서드 오버라이드시 사용되는 예약어 -
new
: 자식클래스에서 동일한 이름의 메서드가 필요할때 사용하는 예약어
오버로드(overload)는 크게 메서드 오버로드와 연산자 오버로드로 나뉜다.
메서드 오버로드(method overload)는 메서드의 시그니처에서 매개변수의 수, 개별 타입만을 재정의 하는 경우를 말한다.
class Mathmatics
{
public int Abs(int value)
{
return (value >= 0) ? value : -value;
}
public double Abs(double value)
{
return (value >= 0) ? value : -value;
}
}
연산자 오버로드(Operator overload)는 해당 연산자를 사용 시 수행되는 메서드를 재정의 하는 것을 말한다.
operator 예약어와 연산자를 사용하여 메서드를 정의한다.
public class Kilogram
{
public static kilogram operator +(Kilogram op1, Kilogram op2)
{
return new Kilogram(op1.mass + op2.mass);
}
}
Kilogram kg1 = new Kilogram(5);
Kilogram kg2 = new Kilogram(10);
Kilogram kg3 = kg1 + kg2;
5. Property
프로퍼티는 접근자 메서드(getter)와 설정자 메서드(setter)에 대한 간편한 구문 표기방법이다.
double pi = 3.14;
public double Pi
{
get { return pi; }
set { pi = value; }
}
6. generic
제네릭 프로그래밍에서의 제네릭(Generic)은 일반화를 의미하며, 데이터 형식에 의존하지 않고 하나의 알고리즘이 여러 데이터 타입을 지원하는 방식을 의미한다.
이러한 방식은 기존의 반복적인 코드를 대체하여 간결하고 재사용성이 높은 코드를 만드는 장점이 있으나, 가독성이 떨어지는 단점이 있다.
C#에서는 제네릭 프로그래밍의 구현을 generic
예약어와 <T>
를 통해 제공한다.
public class NewStack<T>
{
T[] _list;
public void Push(T item) { }
public T Pop() { }
}
<T>
를 사용하여 타입을 지정할 경우 CLR의 JIT 컴파일러는 <T>
에 대응되는 타입으로 대체하여 Native 코드를 생성한다.
따라서 형변환이 발생하지 않아 박싱/언박싱 문제가 없다.
7. partial
C#에서는 코드 분할을 위해 partial
예약어를 제공한다.
class
, struct
, interface
에 사용 가능하며 메서드는 private
으로 선언된 리턴값이 없는 메서드만 적용할 수 있다.
// partical class
partial class Class1
{
public void Run() { }
}
partial class Class2
{
public void Get() { }
}
// partical struct
partial struct Struct1
{
public int ID;
}
partial struct Struct1
{
public string Name;
public Struct1(int id, string name)
{
this.ID = id;
this.Name = name;
}
}
// partical interface
partial interface IDoable
{
string Name { get; set; }
}
partial interface IDoable
{
void Do();
}
// IDoable 인터페이스 사용
public class DoClass : IDoable
{
public string Name { get; set; }
public void Do() { }
}
// partial method
public partial class Class1
{
public void Run()
{
DoThis();
}
partial void DoThis();
}
public partial class Class1
{
partial void DoThis()
{
Log(DateTime.Now);
}
}
Q) string도 equals을 사용하나?
string에서 equals을 사용하면 참조 비교가 아닌 문자열 자체만 비교한다.
참조 비교는 ReferenceEquals 사용
일반적으로 비교연산자나 Compare 사용
http://www.simpleisbest.net/archive/2005/06/08/158.aspx
http://www.hoons.net/Board/cshaptip/Content/17314
Q) GetHashCode는 언제 사용하나?
객체 참조 값 비교를 위해서 사용.
http://msdn.microsoft.com/ko-kr/library/system.object.gethashcode(v=vs.80).aspx
http://vsts2010.tistory.com/232
http://hongjinhyeon.tistory.com/59
특성(Atrribute)
어셈블리(assembly)의 메타데이터에 특성(Atrribute)을 이용하여 코드에 관련된 정보를 남길 수 있다.
checked, unchecked
산술 연산시 오버플로나 언더플로가 발생했을때, 오류를 발생시키거나 발생시키지 않도록 명시하는 예약어
param
메서드의 가변인자 예약어
extern
Win32 API 호출
unsafe
포인터 연산자(*, &) 사용시
fixed
포인터로 인스턴스를 참조하는 경우, 참조 형식의 인스턴스를 GC가 수집하지 못하도록 고정
using
try/finally/Dispose에 대한 간편 표기법