1. C#의 기본문법

1). 데이터 타입

C#의 데이터 타입들은 System.Object에서 파생된 System.Type 에서부터 상속된다. System.Object는 모든 데이터 타입의 부모이고, 어떠한 데이터 타입으로도 변환이 가능하다.

타 입

실제이름

범위

sbyte

System.SByte

-128 ~ 127

byte

System.Byte

0 ~ 255

char

System.Char

하나의 유니코드 문자. U+0000 ~ U+FFFF

short

System.Int16

-32,768 ~ 32,767

ushort

System.UInt16

0 ~ 65,535

int

System.Int32

-2,147,483,648 ~ 2,147,483,647

uint

System.UInt32

0 ~ 4,294,967,295

long

System.Int64

-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807

ulong

System.UInt64

0 ~ 18,446,744,073,709,551,615


타 입

실제이름

정밀도

범 위

float

System.Single

7개의 자릿수

±1.5 ×10~45 ~ ±3.4 × 1038

Double

System.Double

15~16개의 자릿수

±5.0 ×10~324 ~ ±1.7 × 10308

Decimal

System.Decimal

28~29개의 자릿수

1.0 ×10~28 ~ 7.9× 1028

타 입

실제이름

특 징

Object

System.Object

모든 타입의 최상위 부모 클래스. C#에서 모든 객체들은 이 Object 클래스로부터 상속받는다.

String

System.String

문자열을 나타내는 타입이다.

Bool

System.Boolean

Boolean 값이며 참(true) 또는 거짓(false)를 나타낸다.

 

2). 선언의 간략 예

1) 변수선언의 간단 예

int x = 10;

System.Int32 x = 10;

int x, y, z;

string str = "문자열";

※ Delphi와 다른 변수이름 규칙: 대소문자를 가림

2) 구조체 선언

struct Person{

int num;

int age;

double height;

float weight;

}

구조체 변수선언과 값 할당

Person sister;

sister.num = 1000;

sister.age = 15;

sister.height = 165.3D;

sister.weight = 51.0F;

3) 열거형 선언

enum SignFlag {black, yello, green, blue, red};

=> black, yello, green, blue, red는 상수이며, 자동으로 0, 1, 2, 3, 4의 값이 할당된다.

SignFlag s1;

s1 = SignFlag.black;

Console.WriteLine("{0}={1}", s1, (int)s1);

s1 = SignFlag.blue;

Console.WriteLine("{0}={1}", s1, (int)s1);

==> 결과

black=0

blue=3

값을 지정 시: enum SignFlag {black, yello=3, green, blue=7, red};

4) 클래스 선언

class Top{

...

※ 타입캐스팅

class Test
{
    static void Main()
    {
        double x = 1234.7;
        int a;
        a = (int)x;  // cast double to int
        System.Console.WriteLine(a);
    }
}

출력: 1234

 

3). 연산자의 종류

1) 산술연산자

기본 산술연산자: +, -, *, /, %

산술복합연산자: +=, -=, *=, /=

2) 증감/감소 연산자

++x, x++, --y, y--

4) 관계 연산자

==, >, <, <=, >=, !=

5) 논리 연산자

&(AND), |(OR), ^(Exclusive OR), ~(NOT)

&&(Short-Circuit ADN 연산자): 두개의 피연산자 중 첫번째 값이 거짓이면 무조건 거짓이 된다.

||(Short-Circuit OR 연산자): 두개의 피연산자 중 첫번째 값이 참이면 무조건 참이다.

예)

if(a>10 & b>10) {

Consol.WriteLine("AND연산자");

}

if(a>10 && b>10) {

Consol.WriteLine("Short Circuit AND연산자");

}

6) 비트 연산자

&(비트 논리곱 AND), |(비트 논리합 OR), ^(배타적 논리합 XOR), ~ (1의 보수NOT), >>(우측 쉬프트), <<(좌측 쉬프트)

 

4). 제어문 

제어문들은 기본적으로 C문법과 동일

1) if-else문, if-else if, else문

if(불형식의 표현){

참이면 실행할 문장;

} else {

거짓이면 실행할 문장;

}

2) switch case문

int btn;

btn = 2;

switch(btn) {

case 1;

btn이 1일 경우;

break;

case 2:

..

break;

case 3:

...

break;

default:

break;

}

--------------------------------------

int n = 1;
switch (n) {
    case 1:
    case 2:
    case 3:
        Console.WriteLine("1,2,3입니다");
        break;
    default:
        break;
}

3) while문, do-while문

while(조건식) {
      ...
}

--------------------------------

int i = 0;

do{

     Console.WriteLine(i);

     i++;

} while (i > 2);

4) for문

for (int i = 1; i <= 5; i++){

   Console.WriteLine(i);

}

5) foreach 문

int[] numbers = { 4, 5, 6, 1, 2, 3, -2, -1, 0 };

foreach (int i in numbers){

   System.Console.WriteLine(i);

}

//다차원 배열 예 

int[,] numbers2D = new int[3, 2] { { 9, 99 }, { 3, 33 }, { 5, 55 } };
foreach (int i in numbers2D) {
    System.Console.WriteLine("{0} ", i);
}

 

5). 분기문

break, continue

 

 

2. C#의 클래스

 

1). 클래스

 

1) 클래스 만들기와 사용의 간단한 예

using System;

 

public class MethodTest {

public int a;

public int b;

public int Sum(int x, int y) {

return x + y;

}

}

public class MethodMain() {

public static void Main() {

int s;

MethodTest test = new MethodTest();

test.a = 1000;

test.b = 2000;

s = test.Sum(3, 5);

Console.WriteLine("변수 a는 " + test.a);

     Console.WriteLine("변수 b는 " + test.b);

     Console.WriteLine("Sum메서드 결과는 " + test.Sum(3, 5));

     Console.WriteLine("또다른 결과는  " + s);

}

}  

출력:

변수 a는 1000

변수 b는 2000

Sum메서드 결과는 8

또다른 결과는 8

 

2) 접근 지정자

private, protected, public

 

3) 속성(Property)

- 멤버 필드에 값을 할당하는 방법

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

- 스마트 필드(Smart Field)라고도 함

 

using System; 

public class Tes{

private string name; //소문자

public string Name { //대문자

get {

return name;

}

set {

name = value + " 님 반갑습니다.";

}

}

}

 

2). C#에서 구조체와 클래스의 차이점 

 

1) 구조체와 클래스의 유사점

- 클래스와 구조체는 데이터 타입 생성기이다.

 

2) 구조체와 클래스의 차이점

- 구조체는 값(Value Type)이며 클래스는 참조타입(Reference Type)이다.

 

◈ 구조체를 사용하는 이유

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

 

◈ 구조체의 특징

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

- 생성자를 중복해서 만들수 있지만 디폴트 생성자만큼은 재정의 해서 사용할 수 없다.

- (이유)값타입의 변수를 선언함과 동시에 메모리에 생성된다.

 

※ 구조체 테스트

using System;

struct Person {
    public int age;
    public long height;
    public float weight;
    public Person(int a, long h, float w) {
        age = a;
        height = h;
        weight = w;
    }
}

 

public class StructTest {
    public static void Main() {

        Person sister;
        sister.age = 13;
        sister.height = 170L;
        sister.weight = 55F;
        Console.WriteLine("sister : {0}-{1}-{2}", sister.age, sister.height, sister.weight);

 

        Person brother = new Person();//디폴트 생성자
        Console.WriteLine("brother : {0}-{1}-{2}", brother.age, brother.height, brother.weight);

       

        Person mother = new Person(40, 160L, 60F); //초기값을 할당할 수 있는 값타입의 구조체
        Console.WriteLine("mother : {0}-{1}-{2}", mother.age, mother.height, mother.weight);

       

        Person twins = sister; // 값 복사
        Console.WriteLine("twins : {0}-{1}-{2}", twins.age, twins.height, twins.weight);

}

}

 

출력:

sister : 13-170-55

brother : 0-0-0

mother : 40-160-60

twins : 13-170-55

 

==> sister와 twins은 sister를 twins에 통째로 복사된 것

그리고, brother와 mother은 new를 사용하였지만, new를 썼다고 무조건 참조타입은 아니며 값타입으로 생성된 것이다. 구조체의 초기값을 할당할 방법을 제공하기 위해 new 키워드를 사용하였지만, 값타입인 것은 변함없다.

 

 

3). Call By xxx

 

1) 값에 의한 전달 (Call By Value)

-------------------------

int a = 3;

int b = 5;

int c;

c = Sum(a, b);

-------------------------

int Sum(int x, int y) {

return x + y;

}

-------------------------

 

2) ref에 의한 참조 (Call By Reference)

 

using System;

class TestRef {

static void CallByRef(ref int x) {

x = 10000;

}

public static void Main() {

int x1 = 10; //초기화 하지 않으면 에러발생

CallByRef(ref x1);

Console.WriteLine("Call-By-Reference: {0}", x1);

}

}

출력:

Call-By-Reference: 10000

 

◈ ref 키워드

- 참조에 의한 전달을 할 때 사용하는 키워드

- 참조로 값을 넘길 때 참조할 대상은 반드시 초기화 되어야 한다.

 

3) out에 의한 참조(Call By Reference)

 

using System;

class TestRef {

static void CallByRef(out int x) {

x = 10000;

}

public static void Main() {

int x1; //초기화 하지 않음

CallByRef(out x1);

Console.WriteLine("Call-By-Out: {0}", x1);

}

}

출력:

Call-By-Out: 10000

 

◈ out 키워드

- 참조에 의한 전달을 할 때 사용하는 키워드

- 참조로 값을 넘길때 참조할 대상을 초기화 할 필요는 없다.

 

◈ out 키워드를 사용하는 경우

- 함수로부터 값을 얻어낼 때 주로 사용한다. 그렇기 때문에 초기화를 할 필요가 없는 것이다.

 

 

3. C#프로그램 시작하기

 

3-1) C# Hello World 분석

 

1) Hello World 프로그램 구성

 

using System;

namespace org.jabook {

public class HelloWorld {

public static void Main() { // 프로그램 실행은 하나의 Main()에 포함해야한다.

Console.WriteLine("Hello World!");

}

}

}

=> HelloWorld.cs로 저장

 

==> C# 프로그램에서 컴파일을 통해서 만들 수 있는 파일은 exe나 dll 형태의 파일이다. exe 파일은 프로그램의 진입점을 포함하고 있는 형태이며, dll 파일은 진입점을 포함하지 않는 순수한 라이브러리 형태이다. 진입점이 있다는 것은 Main()함수를 포함하고 있다는 의미이다.

 

※ C# 컴파일러로 컴파일하기

Visual Studio 명령프롬프트에서 (VS설치 시)

c:\>csc HelloWorld.cs

HelloWorld.exe가 생성됨 

 

2) 네임스페이스와 어셈블리

 

◈ 어셈브리(Assembly)

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

 

◈ 네임스페이스

: 어셈블리 내에서 각각의 클래스들을 구분하는 기준이 네임스페이스(Namespace)이다. 다시 말해, 어셈블리 내에는 많은 클래스들이 존재할 수 있으며, 이들 클래스를 구분하는 기준이다.

 

namespace aaa{

namespace bbb {

namespace ccc {

public class Person {

public int age;

public long height;

public float weight;

}

}

}

}

 

※ C# 컴파일러로 컴파일하기

csc /target:library /out:Person.dll Person.cs

 

3) 네임스페이스 사용하기

 

◈ 라이브러리 형태의 어셈블리(Assembly)를 사용하기 위한 절차

- Person.dll의 물리적인 위치를 명시한다. (콘솔창에서 컴파일할 때)

- 코드 내에서 Person.dll 내부에서 사용하고자 하는 네임스페이스를 using한다. (코드 내에서 작업)

 

◈ 라이브러리 생성(C#컴파일러)

- csc /target:library /out:Person.dll Person.cs

 

◈ 라이브러리 물리적 사용

- csc /reference:Person.dll /out:PersonFinal.exe PersonTest.cs

- Person.dll이 현재 디렉터리에 있기 때문에 /reference:Person.dll을 사용

- Person.dll이 다른 위치에 있다면 전체 경로 명시

 

◈ 라이브러리의 논리적 사용

  using System;

  using aaa.bbb.ccc; //사용하고자하는 네이스페이스 명시

  public class personTest {

      ...

  }

 

4) Main() 함수

 

C#에서 실행파일이면서 Main() 함수가 없다면 프로그램은 컴파일 되지 않고, 프로그램의 진입점이 없다는 에러가 발생한다.

만약, Main() 함수가 없는 라이브러리 형태의 어셈블리를 만든다면 반드시 컴파일 옵션인 /target:library를 명시해야한다.

 

◈ C#에서 Main() 함수의 형식

1. public static void Main() { .. }

2. public static void Main(string[] args) { .. }

3. public static int Main() { ... return 0; }

4. public static int Main(string[] args) { ... return 0; }

 

◈ Main() 함수의 특징

- 프로그램의 시작점이다.

- Main() 함수가 끝나면 프로그램은 종료한다.

- Main() 함수는 반드시 static으로 선언해야 한다.

- Main() 함수에서 객체를 생성하거나 다른 함수를 호출할 수 있다.

- 명령 프롬프트 상의 매개변수를 읽기 위해서 string 배열을 사용한다.

 

5) static 키워드

모든 클래스에서 공유하기 위한 멤버를 선언하기 위해 사용한다. 객체가 아무리 많이 생성되더라도 스태틱 멤버로 선언되어 있으면 프로그램 내에서 단하나의 메모리만 생성된다. 모든 객체에서 공통으로 사용하는 전역변수의 개념으로 사용할 때 이 스태틱을 사용한다.

 

6) Console.WriteLine() 함수

- System 네임스페이스의 클래스

- WriteLine() 함수는 Colsole 클래스의 스태틱 멤버함수이며 화면에 표준출력을 처리하는 함수

 

예)

Console.WriteLine("a: {0}, b: {1}, a-b: {2}", a, b, a-b);

 

 

3-2) 스태틱 메모리, 함수, 생성자

 

1) 스태틱 메모리

 

◈ 스태틱 사용의 예

public class StaticAccess {

public static in sint = 0;

public int nint = 0;

public static void Main() {

StaticAccess.sint = 3333;

StaticAccess sa = new StaticAccess();

sa.nint = 1000;

Console.WriteLine("static직접접근: " + StaticAccess.sint);

Console.WriteLine("일반멤버 필드접근: " + sa.nint);

}

}

 

◈ 스태틱 메모리에 접근하는 방법

- 클래스의 이름으로 접근한다. (StaticAccess.sint)

 

◈ 스태틱 메모리 생성시기

- 객체를 생성하기 이전에 스태틱의 메모리는 생성된다.

 

2) 스태틱 함수

 

◈ 스태틱 멤버함수

- 스태틱 멤버함수는 클래스의 이름으로 접근 가능하다.

- public static 함수만 접근 가능하다.

 

◈ 스태틱 멤버 함수에서 주의할 점

- 스태틱 함수를 이용하여 일반 멤버 필드에 접근 불가

- 일반 멤버 필드는 객체 생성 후에 존재하기 때문에 스태틱 함수에서 접근 불가

 

◈ 스태틱 함수의 사용

 

public class StatiMethodAccess {

private static int sint = 100;

public int nint = 0;

public static void SetStaticInt(int x) {

sint = x;

}

public static int GetStaticInt() {

return sint;

}

public static void Main() {

StaticMethodAccess.SetStaticInt(33333);

int s = StaticMethodAccess.GetStaticInt();

Console.WriteLine("static값은 : " + s);

}

}

 

3) 스태틱 생성자

 

◈ 스태틱 생성자

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

 

◈ 스태틱 생성자의 특징

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

- 매개변수를 가질 수 없음 : 스태틱에 접근하는 순간 스태틱 생성자는 자동으로 호출되므로 매개변수를 넣어줄 방법이 없다.

 

 

◈ 스태틱 생성자의 사용

 

class StaticConst {

public static int sInt = 0;

static StaticConst() { //스태틱 생성자

sInt = 10;

Console.Write("sInt = " + sInt + " : static 생성자!!");

}

public StaticConst() { //디폴트 생성자

//

}

public static void InitSint(int a) {

sInt = a;

}

}

class StaticConstTest {

public static void Main() {

int a = StaticConst.sInt;

}

}

 

==> 스태틱 멤버 필드들은 클래스가 생성되기 전에 메모리가 생성된다. 그렇다고 한다면 스태틱의 멤버의 값을 초기화할 수 있는 곳은 선언하는 순간에 할당할 수 밖에 없다. 딱히 다른곳에서 할데가 없다 이 방법 이외에 스태틱 생성자라는 것을 이용할 수도 있다.

 

※ Main() 함수가 static 함수인 이유

- 실행 클래스의 객체가 생성되기 이전에 CLR이 Main() 함수에 접근해야 하기 때문이다.

 

 

3-3) const, unsafe

 

1) const 상수 

 

◈ const 키워드

- 상수를 선언하는 키워드

 

◈ const 상수 선언하기의 예

- public const int SALLERY = 7070;

 

◈ const 상수의 특징

- const는 자동으로 static이 된다.

- const로 선언한 변수는 반드시 초기화 되어야 한다.

 

2) readonly 상수

 

 ◈ readonly 상수의 특징

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

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

- static 키워드를 사용하면 스태틱 상수가 되고 사용하지 않으면 일반 상수가 된다.

 

◈ static readonly

- static readonly 일 경우 스태틱 생성자에서 초기화할 수 있다.

- static readonly 일 경우 클래스의 이름으로 접근가능

 

◈ 일반 readonly

- 일반 readonly 일 경우 생성자에서 초기화 할 수 있다.

- 일반 readonly 일 경우 객체의 이름으로 접근가능

 

◈ readonly의 사용

using System;

public class ReadonlyTest {    

public readonly static int STATIC_READONLY = 1;

public readonly int NORMAL_READONLY= 1;

 

static ReadonlyTest() { //static 생성자

STATIC_READONLY = 100;

}

public ReadonlyTest() {//일반 생성자

NORMAL_READONLY = 100000;

}

public static void Main() { //

Console.Write("STATIC_READONLY = " + ReadonlyTest.STATIC_READON

ReadonlyTest rt1 = new ReadonlyTest();

Conesole.Write("NORMAL_READONLY" + rt1.NORMAL_READNLY);

}

}

 

3) 가비지 콜렉터와 메모리

 

◈ c++에서 메모리 관리

- new 를 사용해서 메모리르 생성했으면 반드시 사용자가 직접 delete를 사용해서 메모리를 제거해 주어야한다.

 

◈ 가비지 콜렉터

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

 

◈ 가비지 콜렉터가 하는 일

- 더이상 사용하지 않는 메모리나 불필요한 메모리를 제거한다.

- 메모리가 부족하면 메모리의 조각 모음을 한다.

 

◈ 가비지 콜렉터의 관리 대상

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

 

=> C#에서는 new는 사용하지만 delete는 사용하지 않는다. 가비지 콜렉터를 지원해주기 때문이다. 가비지 콜렉터는 CLR 내에서 동작하면서 메모리의 청소가 필요하다고 생각될 때 시스템에 의해서 구동되는 메모리 청소부와 같은 역할을 담당한다.

 

4) unsafe 코드

 

◈ unsafe code

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

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

 

◈ unsafe code 컴파일 옵션

- unsafe code를 컴파일할 때 컴파일 옵션으로 /unsafe를 사용해서 컴파일해야 한다. 

 

◈ unsafe code 사용

- C#에서 포인터(*)를 사용하기 위해서 unsafe 키워드를 이용해서 사용할 수 있다.

 

using System;

class UnsafeTest {

unsafe static void CallByPoint(int* x) {

*x = 1000;

}

public static void Main() {

int x1 = 10;

unsafe {

CallByPoint(&x1);

}

Console.WriteLine("Call-By-Point: {0}", x1);

}

}

 

4) fixed 키워드를 이용한 메모리 고정

 

◈ fixed 키워드

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

- unsafe code 내에서만 사용할 수 있다.

- CLR이 메모리를 이동하지 않는다는 것이 보장된다.

 

◈ fixed의 사용 예

 

using System;

class FixedTest

{

unsafe static void ArrayCopy(byte[] source, byte[] target) {

fixed(byte* s = source, t = target) {

for( int  i = 0 ; i < source.Lengh ; i++ )

                        *(t+i) = *(s+i);

              }

        }

public static void Main() {

byte[] sample = {5, 6, 4, 6, 3, 4, 100};

byte[] copyed = new byte[7];

ArrayCopy(sample, copyed);

foreach(byte temp in copyed)

Console.Write(temp + "\t");

}

}

결과:

5    6    4    6    3    4    100

 

'프로그래밍 > C#' 카테고리의 다른 글

C#으로 오라클접속  (0) 2012.08.29
C#으로 MySql 접속  (0) 2012.08.28
C#으로 Active Directory 접근  (0) 2012.08.28
C#의 객체지향  (0) 2012.05.10
Posted by 초코송송이
l