1. class
class와 struct는 하나의 논리 단위에 속하는 일련의 data와 behavior을 encapsulate한 데이터 구조이다.
Class TestClass
{
// methods, properties, fields, events, delegates
//and nested classes go here.
public string day; // field
public int f(int x)
{
return x * x; // method
}
}
- field : class 또는 struct 내에 정의된 변수
- method : 나열된 statement를 포함하는 code block. 프로그램은 method를 호출하고 method argument를 지정하여 statement를 실행한다. C#의 모든 실행문은 method에서 수행된다. Main method는 모든 C# application의 entry point이며 프로그램이 시작될 때 CLR에 의해 호출된다.
C# class는 single Inheritance만 허용된다. 그러나 interface는 multiple Inheritance를 받을 수 있다. 
- Access Modifiers
Keyword | |
---|---|
private | class 또는 struct 내부에서만 접근을 허용한다. |
public | class 또는 struct 내부 및 derived class의 접근뿐만 아니라 외부에서도 접근을 허용한다. |
protected | class 또는 struct 내부 및 derived class에서만 접근을 허용한다. |
internal | 동일 assembly 내에서는 public에 준한 접근을 허용한다. |
internal protected | protected와 internal의 조합으로, 동일 assembly 내에서 정의된 derived class까지만 접근을 허용한다. |
nested class가 아닌 class는 public 또는 internal로 선언될 수 있고 기본값은 internal이다.
nested class는 public, protected internal, protected, internal, private로 선언될 수 있고 기본값은 private이다.
2. Interface
class와 struct에 구현될 수 있는 method의 집합을 정의해 놓은 것이다(interfaces can not contain fields).
interface IEquatable<T>
{
bool Equals(T obj);
}
IEquatable interface를 정의할 때는 method signature만 제공하고 IEquatable interface를 상속받는 모든 class 또는 struct는 Equals method를 정의 해야 한다.
interface에 속한 method는 모두 virtual method에 속한다. C# 컴파일러가 interface의 method를 virtual method로 간주하기 때문에 virtual Keyword를 일부러 지정하지 못하게 막고 있다. interface를 상속받은 자식 class에서도 해당 method에 override Keyword를 지정하지 못하게 막고 있다.
method signature : 어떤 method를 고유하게 규정할 수 있는 정보. 구제적으로 method 이름, return type, parameter 수, parameter type이 있다.
3. Inheritance
Inheritance를 사용하면 다른 class에서 정의된 동작을 다시사용, 확장 및 수정하는 새 class를 만들 수 있다. 상속되는 멤버를 base class라고 하고 해당 멤버를 상속하는 class를 derived class라고 한다. derived class는 하나의 base class만 가질 수 있다. 만약 class C 가 class B를 상속받고 class B는 class A를 상속받았다면 class C는 class A, class B에 선언된 멤버를 상속한다(inheritance is transitive).
-
Abstract Base class
new Keyword를 사용하여 instantiation하지 않으려는 class는 Abstract로 선언할 수 있다. Abstract class는 다른 class의 base class로만 사용될 수 있다. Abstract class는 Abstract로 선언된 하나 또는 그 이상의 method signature를 포함할 수 있다. signature는 parameter, return value를 명시하고 있지만 구현(method body)은 포함하지 않는다. Abstract class로 구현할 수 있는 것을 interface라는 Keyword를 만들어 표현하는 이유는 class는 다중 Inheritance가 불가능하기 때문이라고 설명할 수 있다.abstract class ShapesClass { abstract public int Area(); } class Square : ShapesClass { int side = 0; public Square(int n) { side = n; } // Area method is required to avoid // a compile-time error. public override int Area() { return side * side; } static void Main() { Square sq = new Square(12); Console.WriteLine("Area of the square = {0}", sq.Area()); } } // Output: Area of the square = 144
-
Abstract method에는 access Modifier로 private를 지정할 수 없다.
-
Abstract class에 일반 method도 정의할 수 있다.
-
Abstract method는 virtual method에 속하기 때문에 derived class에서 override Keyword를 사용해 재정의한다.
-
Abstract class에 정의된 Abstract method는 derived class에서 반드시 정의해야한다.
-
Derived Class Access to Base Class Members
derived class는 base class의 public, protected, internal, protected internal member에만 접근할 수 있다. -
sealed Keyword
sealed modifier가 선언된 class는 다른 class에서 해당 class inheritance을 받지 못한다.seald class Pen { } public class ElectricPen : Pen { //컴파일 오류 발생 }
-
Derived Class Hiding of Base Class Members
new modifier를 사용하면 derived class에서 같은 이름과 signature로 선언된 base class member를 숨길 수 있다. new modifier를 사용하지 않으면 컴파일 경고가 발생한다.
public class BaseC
{
public int x;
public void Invoke() { }
}
public class DerivedC : BaseC
{
new public void Invoke() { }
}
4. Polymorphism
class Mammal
{
public void Move()
{
Console.WriteLine("이동한다.");
}
}
class Lion : Mammal
{
public void Move()
{
Console.WriteLine("날아다닌다.");
}
}
Lion lion = new Lion();
Mammal one = lion; // 또는 = (Mammal)lion;
one.Move();
//이동한다.
run time 에 derived class의 object가 base class의 object로 type casting 되었을 때, 위의 예제처럼 base class의 개체로 처리될 수 있다. base class에 virtual method를 정의하고 derived class에 override method를 정의하면 run time에 method 호출 시 CLR는 object의 run time type을 찾고, virtual method에 대한 override method를 호출한다. 따라서 소스코드에서 base class에 대한 method를 호출하여 derived class의 method가 실행되도록 할 수 있다.
-
Virtual Members
derived class는 base class member가 virtual 또는 abstract로 선언되었을 경우에만 override 할 수 있다. member는 override keyword를 사용해서 member가 virtual invocation되었다는 것을 명시적으로 표현해야 한다. field는 virtual이 될 수 없다.public class BaseClass { public virtual void DoWork() { } public virtual int WorkProperty { get { return 0; } } } public class DerivedClass : BaseClass { public override void DoWork() { } public override int WorkProperty { get { return 0; } } }
5. Property
class의 field가 public일 때 다른 object에서 직접 field값을 수정할 수 있기 때문에 아래와 같이 field값을 private로 선언해 두고 public mothod GetPi/SetPi를 사용해서 접근 했다.
class Circle
{
double pi = 3.14;
public double GetPi()
{
return pi;
}
public void SetPi(double value)
{
pi = value;
}
}
C#에서는 위와 같이 번거로운 method정의의 단점을 보완하기 위해 Property라는 문법을 제공한다.
class Circle
{
double pi = 3.14;
public double Pi
{
get {return pi;}
set {pi = value;}
}
Circle o = new Circle();
o.Pi = 3.14; // 쓰기
double piValue = o.Pi; // 읽기
value Keyword : C# 컴파일러가 Property에 대입되는 값을 가리킬 수 없는 문제를 해결하기 위해 별도로 set 블록 내부에서만 사용할 수 있는 value Keyword가 도입됐다.
auto-Implemented Properties : C# 3.0에서 auto-Implemented Properties는 property accessor(get, set)에 요구되는 logic이 필요하지 않게 property-declaration을 간략화 했다. public double Pi{get; set;}
와 같이 property를 선언하면 compiler는 get, set accessor로만 접근가능한 private, anonymous backing field를 만듭니다.
C# 6.0에서는 auto-Implemented Properties를 public string FirstName { get; set; } = "Jain"
와 같이 초기화 시킬 수 있다.
6. generic
C# 1.0 문법에서는 primitive types으로 collection object를 사용하는 경우 boxing/unboxing문제가 발생한다.
int n = 5;
ArrayList ar = new ArrayList();
ar.Add(n);
ArrayList는 모든 타입의 collection을 구성할 수 있도록 만들어졌기 때문에 Add method는 prameter로 object type을 받는다. int는 value type이고 object reference type이므로 int 5는 boxing되 heap에 object instance를 할당하고 그 참조 개체가 ArrayList의 Add method에 전달된다.
이 문제를 해결하기 위해 닷넷 프레임워크 2.0에서는 generic이 도입된 새로운 collection type인 List<T>
타입이 발표됐고 아래 예제와 같이 사용한다.
public class GenericList<T>
{
public void Add(T input) { Console.WriteLine(input); }
}
class TestGenericList
{
private class ExampleClass { }
static void Main()
{
// Declare a list of type int.
GenericList<int> list1 = new GenericList<int>();
list1.Add(3);
// Declare a list of type string.
GenericList<string> list2 = new GenericList<string>();
list2.Add("GenericList!");
}
}
7. Partial class
class, struct, method의 정의를 둘 이상의 소스 파일로 분할할 수있다. 각 소스 파일에는 method 또는 type의 definition section이 포함되고, 이 모든 부분은 application 컴파일 시 결합된다. 대규모 프로젝트를 진행하는 경우 class를 개별 파일로 분할하면 여러 프로그래머가 동시에 작업을 수행할 수 있다. Visual Studio에서 자동으로 생성된 소스를 사용하여 작업하는 경우 소스 파일을 다시 만들지 않고도 class에 코드를 추가할 수 있다. 부분이 abstract, sealed로 선언되면 전체 type도 abstract, sealed로 간주되며 부분에 base type이 선언되면 전체 type도 base type을 상속한다.
public partial class Employee
{
public void DoWork()
{
}
}
public partial class Employee
{
public void GoToLunch()
{
}
}
-
Restrictions
-
모든 partial type의 정의는 partial을 사용하여 한정해야 한다.
-
partial modifier는 class, struct, interface Keyword 바로 앞에만 사용할 수 있다.
-
partial-type definition에 중첩된 partial type도 정의될 수 있다.
-
partial class는 같은 accessibility를 가져야 한다(public, priviate).
public partial class A { }
//public class A { } // Error, must also be marked partial
partial class ClassWithNestedClass
{
partial class NestedClass { }
}
partial class ClassWithNestedClass
{
partial class NestedClass { }
}