|
|
### **1. class**
|
|
|
class와 struct는 하나의 논리 단위에 속하는 일련의 data와 behavior을 encapsulate한 데이터 구조이다.
|
|
|
``` cs
|
|
|
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에 의해 호출된다.
|
|
|
|
|
|
<br>
|
|
|
C# class는 single Inheritance만 허용된다. 그러나 interface는 multiple Inheritance를 받을 수 있다.
|
|
|

|
|
|
<br>
|
|
|
|
|
|
* 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).
|
|
|
``` cs
|
|
|
interface IEquatable<T>
|
|
|
{
|
|
|
bool Equals(T obj);
|
|
|
}
|
|
|
```
|
|
|
IEquatable<T> interface를 정의할 때는 method signature만 제공하고 IEquatable<T> 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가 불가능하기 때문이라고 설명할 수 있다.
|
|
|
``` cs
|
|
|
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을 받지 못한다.
|
|
|
``` cs
|
|
|
seald class Pen
|
|
|
{
|
|
|
}
|
|
|
|
|
|
public class ElectricPen : Pen
|
|
|
{
|
|
|
//컴파일 오류 발생
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
* **Derived Class Hiding of Base Class Members**
|
|
|
new modifier를 사용하면 derived class에서 같은 이름과 signature로 선언된 base class member를 숨길 수 있다. new modifier를 사용하지 않으면 컴파일 경고가 발생한다.
|
|
|
``` cs
|
|
|
public class BaseC
|
|
|
{
|
|
|
public int x;
|
|
|
public void Invoke() { }
|
|
|
}
|
|
|
public class DerivedC : BaseC
|
|
|
{
|
|
|
new public void Invoke() { }
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### **4. Polymorphism**
|
|
|
``` cs
|
|
|
class Mammal
|
|
|
{
|
|
|
public void Move()
|
|
|
{
|
|
|
Console.WriteLine("이동한다.");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Lion : Mammal
|
|
|
{
|
|
|
public void Move()
|
|
|
{
|
|
|
Console.WriteLine("날아다닌다.");
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
``` cs
|
|
|
|
|
|
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이 될 수 없다.
|
|
|
|
|
|
``` cs
|
|
|
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를 사용해서 접근 했다.
|
|
|
|
|
|
``` cs
|
|
|
class Circle
|
|
|
{
|
|
|
double pi = 3.14;
|
|
|
|
|
|
public double GetPi()
|
|
|
{
|
|
|
return pi;
|
|
|
}
|
|
|
|
|
|
public void SetPi(double value)
|
|
|
{
|
|
|
pi = value;
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
C#에서는 위와 같이 번거로운 method정의의 단점을 보완하기 위해 Property라는 문법을 제공한다.
|
|
|
``` cs
|
|
|
class Circle
|
|
|
{
|
|
|
double pi = 3.14;
|
|
|
|
|
|
public double Pi
|
|
|
{
|
|
|
get {return pi;}
|
|
|
set {pi = value;}
|
|
|
}
|
|
|
```
|
|
|
``` cs
|
|
|
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문제가 발생한다.
|
|
|
``` cs
|
|
|
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에 전달된다.
|
|
|
<img src="ThirdImage/boxing_arraylist.png" width="350">
|
|
|
|
|
|
이 문제를 해결하기 위해 닷넷 프레임워크 2.0에서는 generic이 도입된 새로운 collection type인 `List<T>`타입이 발표됐고 아래 예제와 같이 사용한다.
|
|
|
``` cs
|
|
|
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을 상속한다.
|
|
|
|
|
|
``` cs
|
|
|
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).
|
|
|
|
|
|
``` cs
|
|
|
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 { }
|
|
|
}
|
|
|
``` |
|
|
\ No newline at end of file |