반응형

안녕하세요.

스레드에서 동시에 같은 메서드에 접근하거나 같은 변수값을 변경할 때, 실행 결과가 잘못될 경우가 있습니다.

이럴때는 쓰레드가 동시에 같은 메서드에 접근을 못하게 하거나 같은 변수에 접근을 못하게 막아야합니다.

이렇게 순차적으로 접근시키고, 동시접근을 막아주는게 동기화라고 할 수 있습니다.

다음 코드는 동기화를 하지 않았을 때 문제가 발생합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication1
{
    class Program
    {
        static int Count = 0;
 
        static void print()
        {
            for (int i = 0; i < 5; i++)
            {
                Count++;
                Console.WriteLine(Count);
                Thread.Sleep(1000);
            }    
        }
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(new ThreadStart(print));
            Thread thread2 = new Thread(new ThreadStart(print));
            Thread thread3 = new Thread(new ThreadStart(print));
            Thread thread4 = new Thread(new ThreadStart(print));
 
            thread1.Start();
            thread2.Start();
            thread3.Start();
            thread4.Start();
 
            thread1.Join();
            thread2.Join();
            thread3.Join();
            thread4.Join();
 
        }
    }
}
cs

4개의 쓰레드를 생성해서 Count 변수에 1씩 5번 더해줘서 총 20을 더하게 됩니다.
근데 출력된 값을 보면 1~20으로 순차적으로 찍히는게 아니라, 다음과 같이 찍히는 경우도 존재합니다.

제대로 연산이 안될 경우가 있으면, 계속 버그가 만들어지게 되므로, 우리는 항상 규칙적으로 코드가 실행되야 합니다.

그래서 동기화를 사용해서 한 쓰레드가 메모리에 접근중이면 다른 쓰레드가 해당 메모리에 접근하지 못하도록 막습니다.

동기화에는 다음과 같은 클래스를 사용합니다.

1. Lock

상호 배제 잠금을 획득하여, 명령문 브록을 실행 후, 잠금을 해제합니다.
잠금을 보유하는 스레드에서 잠금을 다시 해제할 수 있으며, 
다른 스레드에서는 잠금을 획득이 차단되고, 잠금이 해제될때까지 대기하게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication1
{
    class Program
    {
        static int Count = 0;
 
        static System.Object lockThis = new System.Object();
 
        static void print()
        {
            lock (lockThis)
            {
                for (int i = 0; i < 5; i++)
                {
                    Count++;
 
                    Console.WriteLine(Count);
                }
            }
        }
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(new ThreadStart(print));
            Thread thread2 = new Thread(new ThreadStart(print));
            Thread thread3 = new Thread(new ThreadStart(print));
            Thread thread4 = new Thread(new ThreadStart(print));
 
            thread1.Start();
            thread2.Start();
            thread3.Start();
            thread4.Start();
 
            thread1.Join();
            thread2.Join();
            thread3.Join();
            thread4.Join();
 
        }
    }
}
cs

2. Monitor

Lock과 같이 해당 블록을 잠금 후 실행하고, 잠금을 해제합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication1
{
    class Program
    {
        static int Count = 0;
        static Object monitorLock = new System.Object();
 
        static void print()
        {
            Monitor.Enter(monitorLock);
            try
            {
                for (int i = 0; i < 5; i++)
                {
                    Count++;
                    Console.WriteLine(Count);
                    Thread.Sleep(1000);
                }
            }
            finally
            {
                Monitor.Exit(monitorLock);
            }
        }
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(new ThreadStart(print));
            Thread thread2 = new Thread(new ThreadStart(print));
            Thread thread3 = new Thread(new ThreadStart(print));
            Thread thread4 = new Thread(new ThreadStart(print));
 
            thread1.Start();
            thread2.Start();
            thread3.Start();
            thread4.Start();
 
            thread1.Join();
            thread2.Join();
            thread3.Join();
            thread4.Join();
 
        }
    }
}
cs

Monitor 클래스 중에는 Wait()와 Pulse() 메서드가 있습니다.
쓰레드를 Wait() 메서드로 잠시 대기상태로 만들어 준 후 Pulse()로 활성화 시킬 수 있습니다.
보통 메모리 상에 데이터를 가질때까지 대기하고 데이터를 가지게 되면 활성화 시켜서 작업을 진행할 수 있도록 할 수 있습니다.
다음은 Count 필드 값을 순차적으로 증가 시킨 후 다른 스레드에서 감소합니다.

반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] 스레드(Thread)  (0) 2019.11.04
[C#]컬렉션(Collections)  (0) 2019.10.31
C# 인터페이스(interface)  (0) 2019.10.30
[C#] 배열(Array)  (0) 2019.10.29
[C#] String.Format  (0) 2019.10.28
반응형

스레드는 프로세스 내에서 실행되는 흐름의 단위를 말합니다.
프로세스 내에는 여러 개의 스레드가 존재할 수 있습니다.

그리고 여러개의 스레드로 여러 작업 들을 실행할 수 있습니다.
예를 들면, 어떠한 연산을 동시에 실행되게 할 수 있습니다.

동시에 연산을 진행하게 되면 다른 연산 결과를 얻을 수 있으므로 제대로 된 설계를 하여 스레드를 사용해야 합니다. 스레드는 프로세스 내에서 실행되는 흐름의 단위를 말합니다.
프로세스 내에는 여러 개의 스레드가 존재할 수 있습니다.

그리고 여러개의 스레드로 여러 작업 들을 실행할 수 있습니다.
예를 들면, 어떠한 연산을 동시에 실행되게 할 수 있습니다.

동시에 연산을 진행하게 되면 다른 연산 결과를 얻을 수 있으므로 제대로 된 설계를 하여 스레드를 사용해야 합니다.

바로 예제 코드 작성을 하여, 설명드리겠습니다.

다음과 같이 코드를 작성하면 쓰레드가 만들 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void print()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("out : {0}", i);
                Thread.Sleep(1000);
            }
        }
        static void Main(string[] args)
        {
            Thread thread = new Thread(new ThreadStart(print));
 
            thread.Start();
            
        }
    }
}
cs

using System.Threading를 사용하여 Thread클래스를 생성할 수 있습니다.

new Thread(new ThreadStart(print))로 스레드로 생성할 메서드를 델리게이트를 만들어서 스레드를 생성합니다.

thread.Start();로 시작합니다.

순차적으로 out : 0 ~ out : 5까지 출력되는것을 확인할 수 있습니다.

Main에서 print함수를 같이 실행 시켜봅니다.

1
2
3
4
5
6
7
8
static void Main(string[] args)
{
    Thread thread = new Thread(new ThreadStart(print));
 
    thread.Start();
 
    print();    // 이부분만 추가합니다.
}
cs

이렇게 한다면 새로 만든 print메서드를 사용하는  thread와 메인 스레드 두개가 동시에 진행되면서,
out : 0 ~ out : 5가 2개씩 찍히는 것을 확인할 수 있습니다.

쓰레드 실행 중에 종료를 하면 어떻게 할까요??

바로 Abort함수를 이용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void print()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("out : {0}", i);
                Thread.Sleep(1000);
            }
        }
        static void Main(string[] args)
        {
            Thread thread = new Thread(new ThreadStart(print));
 
            thread.Start();
 
            Thread.Sleep(3000);
            thread.Abort();
            thread.Join();    // 종료대기
        }
    }
}
cs

이렇게 코드를 작성하면 3초 후 종료가 되어서 print메서드의 출력을 모두 할 수 없습니다.

Abort()를 호출하면, ThreadAbortException를 throw 하여 종료가 됩니다.

근데 Abort()는 지금 같이 간단한 코드에서는 문제가 생기지 않지만, 

바로 종료가 된다는 보장도 없으며, Join함수로 인해 종료 대기가 된다는 보장도 없습니다.

웬만하면 Abort()를 이용해서 종료하지 않는 편이 좋습니다.

다음과 같이 작성하면 throw 할 때 상태를 확인할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void print()
        {
            try
            {
                for (int i = 0; i < 5; i++)
                {
                    Console.WriteLine("out : {0}", i);
                    Thread.Sleep(1000);
                }
            }
            catch (ThreadAbortException e )
            {
                Console.WriteLine(e);
            }
            finally
            {
                Console.WriteLine("About Complete");
            }
        }
        static void Main(string[] args)
        {
            Thread thread = new Thread(new ThreadStart(print));
 
            thread.Start();
 
            Thread.Sleep(3000);
            thread.Abort();
            thread.Join();    // 종료대기
        }
    }
}
cs
반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] 스레드 동기화(Lock, Monitor)  (0) 2019.11.05
[C#]컬렉션(Collections)  (0) 2019.10.31
C# 인터페이스(interface)  (0) 2019.10.30
[C#] 배열(Array)  (0) 2019.10.29
[C#] String.Format  (0) 2019.10.28
반응형
 

데이터들은 한 그룹으로 모아서 관리할때 배열을 만들거나 컬렉션을 만들어서 관리를 하게됩니다.

하지만 배열은 초기에 데이터크기를 정해서 사용해야하기때문에 유동성있게 데이터를 추가/삭제가 편리하게 구성되어있는 컬렉션을 사용할 수 있습니다.

컬렉션은 System.Collections.Generic 네임스페이스의 using하여 사용할수있습니다.

컬렉션 종류
Dictionary<TKey,TValue>키에 따라 구성된 키/값 쌍의 컬렉션을 나타냅니다.
List<T>인덱스로 액세스할 수 있는 개체 목록을 나타냅니다. 목록의 검색, 정렬 및 수정에 사용할 수 있는 메서드를 제공합니다.
Queue<T>FIFO(선입선출) 방식의 개체 컬렉션을 나타냅니다.
SortedList<TKey,TValue>연관된 IComparer<T> 구현을 기반으로 키에 따라 정렬된 키/값 쌍의 컬렉션을 나타냅니다.
Stack<T>LIFO(후입선출) 방식의 개체 컬렉션을 나타냅니다.
ArrayList필요에 따라 크기가 동적으로 증가하는 개체 배열을 나타냅니다.
Hashtable키의 해시 코드에 따라 구성된 키/값 쌍의 컬렉션을 나타냅니다.
QueueFIFO(선입선출) 방식의 개체 컬렉션을 나타냅니다.
StackLIFO(후입선출) 방식의 개체 컬렉션을 나타냅니다.
반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] 스레드 동기화(Lock, Monitor)  (0) 2019.11.05
[C#] 스레드(Thread)  (0) 2019.11.04
C# 인터페이스(interface)  (0) 2019.10.30
[C#] 배열(Array)  (0) 2019.10.29
[C#] String.Format  (0) 2019.10.28
반응형
인터페이스는 클래스와 비슷하지만, 메서드, 이벤트, 인덱서, 속성을 클래스에서 가질 수 있는 기능들을 정의하지만, 구현은 하지않습니다.
 
구현을 인터페이스를 갖는 클래스에서 반드시 해야합니다.
이렇게 쓰는 이유는 인터페이스 하나만으로 내가 구현부를 알지못해도 사용이 가능하도록 하고, 
이런 기능들이 클래스에서 꼭 사용되야한다고 명시한다고 볼 수도 있습니다.
 
추상 base 클래스와 매우 유사하지만, 클래스는 다중상속을 지원하지 않지만 인터페이스는 다중상속을 지원합니다
또한 구조체는 다른 구조체나 클래스를 상속할 수 없지만 인터페이스는 지원합니다.
 
형식
public interfase 인터페이스명
{
int 메서드이름();
}
 
구현
인터페이스를 갖는 클래스의 경우 인터페이스에서 정의한 메서드등을 반드시 구현해야합니다.
public interface IAAAA
{
void print();
}
 
public class BBBB : IAAAA
{
public void print()
{
Console.WriteLine("print()");
}
}
 

 

인터페이스는 클래스와 비슷하지만, 메서드, 이벤트, 인덱서, 속성을 클래스에서 가질 수 있는 기능들을 정의하지만, 구현은 하지 않습니다.

구현을 인터페이스를 갖는 클래스에서 반드시 해야합니다.
이렇게 쓰는 이유는 인터페이스 하나만으로 내가 구현부를 알지 못해도 사용이 가능하도록 하고, 
이런 기능들이 클래스에서 꼭 사용되야한다고 명시한다고 볼 수도 있습니다.

추상 base 클래스와 매우 유사하지만, 클래스는 다중상속을 지원하지 않지만 인터페이스는 다중 상속을 지원합니다
또한 구조체는 다른 구조체나 클래스를 상속할 수 없지만 인터페이스는 지원합니다.

형식
public interfase 인터페이스명
{
int 메서드이름();
}

구현
인터페이스를 갖는 클래스의 경우 인터페이스에서 정의한 메서드 등을 반드시 구현해야 합니다.
public interface IAAAA
{
void print();
}

public class BBBB : IAAAA
{
public void print()
{
Console.WriteLine("print()");
}
}


인터페이스로 정의를 하면 인터페이스 맴버만 접근이 가능합니다.

public interface IAAAA
{
void print();
}

public class BBBB : IAAAA
{
public void print()
{
Console.WriteLine("print()");
}

public void print2()
{
Console.WriteLine("print()2");
}
}

static void Main(string[] args)
{
IAAAA B1 = new BBBB();
B1.print();
//B1.print2();
}

B1.print2();가 접근이 불가능합니다.

접근이 가능하려면 
IAAAA B1 = new BBBB(); 이 부분을 BBBB B1 = new BBBB(); 이렇게 수정하면 됩니다.

반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] 스레드(Thread)  (0) 2019.11.04
[C#]컬렉션(Collections)  (0) 2019.10.31
[C#] 배열(Array)  (0) 2019.10.29
[C#] String.Format  (0) 2019.10.28
[C#] #region  (0) 2019.10.27
반응형

배열
형식이 동일한 변수를 여러개 저장이 가능하도록 모아놓은 데이터 집합입니다.

형식
type[] arrayName;

속성
- 1차원, 혹은 다차원 또는 가변으로 만들 수 있습니다.
- 차원 수와 각 차원 길이는 배열 인스턴스를 만들 때 설정되는데, 인스턴스 수명동안 변경이 불가능합니다.
- 숫자(int형) 배열 요소의 기본값은 0으로 설정되고, 참조 요소는 null로 설정됩니다.
- 가변 배열은 요소들이 참조형식이며, null로 초기화됩니다.
- 배열은 0으로 인덱싱되고, 요소들은 0~n-1로 인덱싱됩니다.
- 배열 형식은 Array 추상 기본 형식에서 파생된 참조 형식입니다. 이 형식은 IEnumerable 및 IEnumerable을 구현하므로 foreach반복을 사용할 수 있습니다.


1차원 배열

다음과 같이 선언할 수 있습니다.
int[] arrayName = new int[10]

배열 선언 시 배열 초기값을 설정은 다음과 같이 할 수 있습니다.
int[] arrayName = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

다음과 같이 초기화 하지 않고 배열을 선언하고 배열을 할당할 때 값을 설정할 수도 있습니다.
int[] arrayName;
arrayName = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

특정 배열요소에 접근할때에는 인덱스로 접근합니다.
예를들어, 위에 arrayName에 5값을 접근하려면 arrayName[4]로 접근할 수 있습니다.


다차원 배열

2차원 배열은 다음과 같이 선언할 수 있습니다.
int[,] arrayName = new int[5, 2];

3차원 배열은 다음과 같이 선언할 수 있습니다.
int[, ,] = arrayName = new int [5, 2, 4];

초기화는 다음과 같이 할 수 있습니다.
int[,] array2 = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 9, 10 } }; 

int[,] array2a = new int[5,2] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 9, 10 } };

int[,] array2b =  { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 9, 10 } };

특정 배열요소로의 접근은 다음과 같이 할 수 있습니다.
array2[2, 1] = 9;
array2a[2, 1] = 9;
arraarray2b[2, 1] = 9;

가변 배열

가변 배열의 요소들은 차원과 크기가 다를 수 있습니다.

다음과 같이 선언해서 설정합니다.

int[][] arrayName = new int [2][];
arrayName[0] = new int[4];
arrayName[1] = new int[2];

초기값을 넣어서 값을 채울 수 있습니다.
int[][] arrayName = new int [2][];
arrayName[0] = new int[] { 1, 2, 3, 4 };
arrayName[1] = new int[] { 5, 6 };

다음과 같이 선언시에 초기화할 수도 있습니다.
int[][] arrayName = new int [][]
{
    new int[] { 1, 2, 3, 4 },
    new int[] { 5, 6 }
};

new int[][]를 다음과 같이 생략할 수 있습니다.
int[][] arrayName = 
{
    new int[] { 1, 2, 3, 4 },
    new int[] { 5, 6 }
};

배열 요소에 접근하려면 다음과 같이 하면됩니다.
arrayName[0][1] = 5;

서로 다른 크기의 세가지 2차원 배열을 만들 수 도있습니다.
int[][,] arrayName = new int[3][,]
{
    new int[,] { {1, 2}, {3, 4} },
    new int[,] { {5, 6}, {7, 8}, {9, 10} },
    new int[,] { {11, 12}, {13, 14}, {15, 16}, {17, 18} }
};
Console.WriteLine(arrayName[2][1, 0]);
출력:13

Length를 이용해서 가변 배열에 포함된 배열수를 알 수 있습니다.
Console.WriteLine(arrayName.Length);
이렇게 한다면 3이 출력됩니다.

Length를 이용해서 가변값을 다음과 같이 출력할 수 있습니다.

int[][] arrayName = new int[][]
{
    new int[] { 1, 2, 3, 4 },
    new int[] { 5, 6 }
};

for (int i = 0; i < arrayName.Length; i++)
{
    for ( int j = 0; j < arrayName[i].Length; j++ )
        Console.Write("{0} ", arrayName[i][j]);
        System.Console.WriteLine();
}


foreach 사용
foreach문을 사용하여 배열의 데이터를 가져올 수 있습니다.

다음과 같이 사용할 수 있습니다.
int[] arrayName = new int[]{1,2,3,4,5};

foreach (int i in arrayName)
    Console.Write("{0} ", i);

배열을 인수로 전달

배열을 함수 인수로 전달할 수 있습니다.
int[] arrayName = new int[]{1,2,3,4,5};
printArray(arrayName);

static void printArray(int[] arr)
{
    foreach(int i in arr)
    Console.Write("{0} ", i);
}

반응형

'개발공부 > C#' 카테고리의 다른 글

[C#]컬렉션(Collections)  (0) 2019.10.31
C# 인터페이스(interface)  (0) 2019.10.30
[C#] String.Format  (0) 2019.10.28
[C#] #region  (0) 2019.10.27
[C#] 익명 타입(Anonymous Types)  (0) 2019.10.23
반응형

문자열을 나타낼 때 String에 데이터를 넣고 사용할 수 있습니다.
다양한 형태로 사용하려면 String의 Format함수를 이용합니다.

다음과 같이 사용할 수 있습니다.
String str;
str = String.Format("{0}", 1);
Console.WriteLine(str);
출력 : 1

두 개의 항목을 스트링에 넣으려면 {1}을 추가하면 됩니다.
String str;
str = String.Format("{0}, {1}", 1, 7);
Console.WriteLine(str);
출력 : 1, 7

서식으로도 넣을 수 있습니다.
String str;
str = String.Format("{0:D5}", 7);
Console.WriteLine(str);
출력:00007
D5같이 해당 항목에 서식으로 넣을 수 있게됩니다.
다음과 같은 서식이 있습니다.
"C" 또는 "c" - 통화형식 언어가 우리나라로 지정되어있을 경우 '\'가 앞에 붙어서 표기됩니다.
"D" 또는 "d" - 정수형식 1234을 D로 했을 경우 1234, D5로 했을 경우 01234로 표기됩니다.
"E" 또는 "e" - 지수형식 12345.6789691226 E로 했을 경우 1.234568E+004, e로 했을 경우 1.234568e+004로 표기됩니다. 또한 E2는 1.23E+004로 표기됩니다.
"F" 또는 "f" - 고정소수점형식 1234.567를 F로 했을 경우 1234.56, 1234.56을 F4로 했을 경우 1234.5600로 표기됩니다.
"G" 또는 "g" - 모든 숫자 형식 12345.6789를 G로 지정하면 12345.6789로 표기되지만, G2하면 1.2E+04로 표기가 됩니다.
"N" 또는 "n" - 자릿수를 지정합니다. 1234.567을 N으로 지정하면 1,234.567로 표기되고, N4로 지정하면 1,234.5670으로 표기됩니다.
"P" 또는 "p" - 100으로 곱하고 백분율 기호와 함께 표시합니다. 1을 P로 지정하면 100%로 표기됩니다.
"R" 또는 "r" - 해당 숫자로 라운드트립할 수 있는 문자. BigInteger형식에만 권장됩니다. 
"X" 또는 "x" -  16진수 형식. 10을 X로 지정하면 A로 표기됩니다.

간격을 제어할 수 있습니다.
String str;
str = String.Format("{0,10} {1,5}", 10, 2);
Console.WriteLine(str);

반응형

'개발공부 > C#' 카테고리의 다른 글

C# 인터페이스(interface)  (0) 2019.10.30
[C#] 배열(Array)  (0) 2019.10.29
[C#] #region  (0) 2019.10.27
[C#] 익명 타입(Anonymous Types)  (0) 2019.10.23
[C#] Action, Func  (0) 2019.10.22
반응형
안녕하세요

오늘은 스크립트를 보기좋게 단락별로 구분할 수 있는 "#region"에 대해서 알아보도록 하겠습니다.

코드가 몇천줄만 넘어도 코드가 한눈에 들어오기가 어렵게되는데 이럴때 유용하게 사용할수 있습니다.

코드가 어떤코드인지 제목을 넣을수 있고 현재 작업중인 코드에 집중하기 위해 영역을 축소하거나 숨길수 있습니다.

형식
#region 제목
내용
#endregion

예제
#region class AAA
public class AAA
{
     int nNum;
}
#endregion

이렇게 간단하게 사용할 수 있습니다.
반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] 배열(Array)  (0) 2019.10.29
[C#] String.Format  (0) 2019.10.28
[C#] 익명 타입(Anonymous Types)  (0) 2019.10.23
[C#] Action, Func  (0) 2019.10.22
[C#] 람다식(Lambda expressions)  (0) 2019.10.21
반응형

명시적으로 데이터 타입을 정의할 필요 없이 읽기 전용 속성 집합을 단일 개체로 편리하게 캡슐화가 가능합니다.
타입은 컴파일러에 의해 생성되고, 소스 코드 수준에서 값을 변경할 수 없습니다.
속성을 초기화하는데 사용되는 식은 null, 익명 함수 또는 포인터 형식일 수 없습니다.

형식
var 변수명 = new { 속성 = 값, 속성 = 값,....}

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var a = new { num1 = 50, strMessage = "HI" };
            //a.num1 = 20; 읽기전용이므로 할당이 불가능합니다.
            Console.WriteLine("a.num1 = " + a.num1);
            Console.WriteLine("a.strMessage = " + a.strMessage);
        }
    }
}
 
 

a란 변수를 만들어 num1, strMessage라는 속성을 가진 값을 만들 수 있습니다.

읽기전용이므로 "a.num1 = 20;"와 같이 값을 할당할 수 없습니다.

또한 다음과 같이 배열형식으로 넣을 수 있습니다.

var a = new[] { new { num1 = 50, strMessage = "Kim"}, new { num1 = 100, strMessage = "Lee"} }

 

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var a = new[] { new { num1 = 50, strMessage = "Kim"},
                            new { num1 = 100, strMessage = "Lee"},
                            new { num1 = 150, strMessage = "Choi"},
                            new { num1 = 2500, strMessage = "Jung"},
                            new { num1 = 3050, strMessage = "Park"}
                            };
            foreach (var aaaa in a)
            {
                Console.WriteLine("a.num1 = " + aaaa.num1);
                Console.WriteLine("a.strMessage = " + aaaa.strMessage);
            }
        }
    }
}
 
 

LINQ 쿼리 식을 사용해서 데이터 조회도 가능합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var a = new[] { new { num1 = 50, strMessage = "Kim"},
                            new { num1 = 100, strMessage = "Lee"},
                            new { num1 = 150, strMessage = "Choi"},
                            new { num1 = 2500, strMessage = "Jung"},
                            new { num1 = 3050, strMessage = "Park"}
                            };
            var list = a.Where(p => p.num1 > 1000).Select( p=> new { p.num1, p.strMessage } );
            foreach (var aaaa in list)
            {
                Console.WriteLine("a.num1 = " + aaaa.num1);
                Console.WriteLine("a.strMessage = " + aaaa.strMessage);
            }
        }
    }
}
 
반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] String.Format  (0) 2019.10.28
[C#] #region  (0) 2019.10.27
[C#] Action, Func  (0) 2019.10.22
[C#] 람다식(Lambda expressions)  (0) 2019.10.21
[C#] 무명 메서드(anonymous method)  (0) 2019.10.20
반응형

 

안녕하세요. 개발남입니다. 

 

알기 쉬운 C#  Action, Func입니다.

 

델리게이트를 생성하기 위해 필요한 델리게이트 형태에 맞춰서 미리 선언해줘야하는데,
만약 무명 메소드로 잠깐 사용하거나 델리게이트 형태가 많은 경우 모두 선언해줘야하는 불편함이있습니다.
C#에서는 이런 불편함을 없애기위해 Func와 Action delegate가 미리 선언되어있습니다.

Action - 매개 변수를 0~16개 가질 수 있는 값을 반환하지 않는 메서드를 캡슐화
Func - 매개 변수를 0~16개를 가질 수 있는 값을 반환하는 메서드를 캡슐화


형태
Action
public delegate void Action<입력 매개변수> (매개변수);

Func
public delegate 반환형 Func<입력 매개변수,반환형> (매개변수);

 

예제
Action

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
 
    class Program
    {
        static void Main(string[] args)
        {
            Action output1 = () => Console.WriteLine("AAAA");
            output1();
 
            Action<int> output2 = (v) => Console.WriteLine(v);
            output2(2);
        }
    }
}
 
 

Func

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    delegate void DelegateParameterTwo(int n1, int n2);
 
    class Program
    {
        static void Main(string[] args)
        {
            Func<int> value = () => 2+8;
            Console.WriteLine(value());
            Func<intintint> plus = (n1, n2) => n1 + n2;    
            Console.WriteLine(plus(27));
            Func<intintfloat> minus = (n1, n2) => n1 * n2 * 0.5f; 
            Console.WriteLine(minus(67));
        }
    }
}
 
 

 

반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] #region  (0) 2019.10.27
[C#] 익명 타입(Anonymous Types)  (0) 2019.10.23
[C#] 람다식(Lambda expressions)  (0) 2019.10.21
[C#] 무명 메서드(anonymous method)  (0) 2019.10.20
[C#] 제네릭  (0) 2019.10.19
반응형

 

 

무명 메서드와 비슷하게 이름 없이 함수를 표현할 수 있습니다.

형식
(입력 파라메터) => { 실행문 } 

실행문이 한개일때는 중괄호 없이 표현합니다.

(입력 파라메터) => 실행문

입력 파라메터에는 0개부터 여러 개까지 다양하게 만들 수 있습니다.

보통 Delegate를 이용해서 사용합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    delegate void AAAA();
 
    class Program
    {
        static void Main(string[] args)
        {
            AAAA output = () => Console.WriteLine("AAAA");
            output();
        }
    }
}
 

파라메터에 여러 개를 넣을 수 있습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    delegate void AAAA1();
    delegate void AAAA2(int nNum);
 
    class Program
    {
        static void Main(string[] args)
        {
            AAAA1 output1 = () => Console.WriteLine("AAAA");
            output1();
 
            AAAA2 output2 = (v) => Console.WriteLine(v);
            output2(2);
        }
    }
}
 
 

 

람다식에 여러 실행문을 넣을 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    delegate void DelegateParameterTwo(int n1, int n2);
    
    class Program
    {
        static void Main(string[] args)
        {
            DelegateParameterTwo plus = (n1, n2) => { int n3 = n1 + n2; Console.WriteLine(n3); };
            plus(27);
 
            DelegateParameterTwo minus = (n1, n2) => { int n3 = n1 - n2; Console.WriteLine(n3); };
            minus(127);
        }
    }
}
 
 

 

반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] 익명 타입(Anonymous Types)  (0) 2019.10.23
[C#] Action, Func  (0) 2019.10.22
[C#] 무명 메서드(anonymous method)  (0) 2019.10.20
[C#] 제네릭  (0) 2019.10.19
[C#] 인덱서(Indexer)  (0) 2019.10.18
반응형

델리게이트(delegate)에 미리 정의하지 않아도 되는 메서드명이 없는 메서드로 정의하지 않고 중괄호안에 명령문만 넣어서 간편하게 구현할수 있습니다.
인라인 메서드와 비슷한 형식을 보입니다.

형식
delegate( 매개변수 ) { 실행문 }

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    class Program
    {
        delegate void printNum(int nNum);
        static void Main(string[] args)
        {
 
            printNum print = delegate ( int nNum )
            {
                Console.WriteLine(nNum);
            };
 
            print(5);
        }
    }
}
 
 


다음과 같이 이벤트와 같이 사용하면서 넣을 수도 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    delegate void PrintNum(int nNum);
 
    class AAA
    {
        public event PrintNum print;
        public void totalOutPut()
        {
            print(5);
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            AAA aaa = new AAA();
 
            aaa.print += delegate(int nNum)
            {
                Console.WriteLine(nNum);
            };
 
            aaa.print += delegate(int nNum)
            {
                Console.WriteLine(nNum * nNum);
            };
 
            aaa.totalOutPut();
        }
    }
}
 
s
반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] Action, Func  (0) 2019.10.22
[C#] 람다식(Lambda expressions)  (0) 2019.10.21
[C#] 제네릭  (0) 2019.10.19
[C#] 인덱서(Indexer)  (0) 2019.10.18
[C#] 이벤트(event) & 델리게이트(delegate)  (0) 2019.10.17
반응형

C# 제네릭 (C# Generics)
클래스 또는 메서드(함수)를 선언하고 인스턴스화 할때까지 하나이상의 형식을 따르는 클래스나 메서드(함수)를 디자인할 수 있도록 형식 매개 변수 개념을 도입할 수 있습니다. 

 

보통 사칙연산등에서 변수타입에서 관련 없이 함수의 매개변수에 값을 넣어 다용도로 사용할 수 있게 만들기 위해 사용합니다.
C++에 템플릿하고 비슷한 역할을 수행합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    class AAAA<T>
    {
        public void print(T value)
        {
            Console.WriteLine(value);
        }
        
    }
    class Program
    {
        static void Main(string[] args)
        {
            AAAA<int> aaaaInt = new AAAA<int>();
            aaaaInt.print(1);
            AAAA<string> aaaaString = new AAAA<string>();
            aaaaString.print("AAAAA");
        }
    }
}
 
 

위 예제는 클래스 함수에 템플릿을 사용한 예를 보여줍니다.
int형과 string형에 관련없이 해당 값을 출력할 수 있도록 구현되었습니다.

반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] 람다식(Lambda expressions)  (0) 2019.10.21
[C#] 무명 메서드(anonymous method)  (0) 2019.10.20
[C#] 인덱서(Indexer)  (0) 2019.10.18
[C#] 이벤트(event) & 델리게이트(delegate)  (0) 2019.10.17
[C#] delegate  (0) 2019.10.16
반응형

C# 인덱서(Indexer)
C# 인덱서(Indexer)는 클래스나 구조체의 데이터를 배열처럼 인덱스로 접근이 가능하도록 구현을 할 수 있게 합니다.

정의 
this[]를 사용하여 속성처럼 get과 set으로 정의합니다.

 

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    class AAAA
    {
        private int[] num = new int[10];
        public int this[int nIndex]
        {
            get
            {
                if (nIndex < 0 || nIndex > 10)
                {
                    throw new IndexOutOfRangeException();
                }
                else
                {
                    return num[nIndex];
                }
            }
            set
            {
                if (nIndex < 0 || nIndex > 10)
                {
                    throw new IndexOutOfRangeException();
                }
                else
                {
                    num[nIndex] = value;
                }
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            AAAA aaaa = new AAAA();
            aaaa[0= 2;
            Console.WriteLine(aaaa[0]);
        }
    }
}
 
 

위와 같이 클래스에 배열변수를 인덱서를 이용해서 접근해서 get / set이 가능하도록 만들 수 있습니다.


C# 6(Visual Studio 2015)부터는 이 구문 대신


public int this[int nIndex] => num[nIndex];

이렇게 표현할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public int this[int nIndex]
{
    get
    {
        if (nIndex < 0 || nIndex > 10)
        {
            throw new IndexOutOfRangeException();
        }
        else
        {
            return num[nIndex];
        }
    }
    set
    {
        if (nIndex < 0 || nIndex > 10)
        {
            throw new IndexOutOfRangeException();
        }
        else
        {
            num[nIndex] = value;
        }
    }
}
 
s

 

C# 7.0(Visual Studio 2017)부터 get 및 set 접근자 모두 본문 멤버로 구현할 수 있습니다.

1
2
3
4
5
public T this[int nIndex]
{
    get => num[nIndex]; 
    set => num[nIndex] = value; 
}
 
반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] 무명 메서드(anonymous method)  (0) 2019.10.20
[C#] 제네릭  (0) 2019.10.19
[C#] 이벤트(event) & 델리게이트(delegate)  (0) 2019.10.17
[C#] delegate  (0) 2019.10.16
[C#] Event  (0) 2019.10.15
반응형

델리게이트(delegate)의 문제
- 추가 연산(+=)을 하려고 했는데, 할당 연산(=)을 하는 경우 이전에 추가했던 함수 리스트들이 사라지는 문제
- 외부에서 접근제한이 없다면 함수와 같이 호출이 가능하게 된다.

위와 같은 문제를 해결하기 위해 event를 사용합니다.
이벤트(event)는 외부에서 추가나 차감 연산만 가능합니다.
이벤트(event)는 외부에서 직접 호출이 아닌 함수를 통한 호출을 해야합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    delegate void Print(string strContent);
    class AAA
    {
        public event Print print;
 
        public void DelegatePrintAAA1(string strContent)
        {
            Console.WriteLine("AAA1" + strContent);
        }
        public void DelegatePrintAAA2(string strContent)
        {
            Console.WriteLine("AAA2" + strContent);
        }
        public void DelegatePrintAAA3(string strContent)
        {
            Console.WriteLine("AAA3" + strContent);
        }
 
        public void totalOutput()
        {
            if (this.print != null)
            {
                print("11111");
            }
        }
    }
    class Program
    {
        static void DelegatePrint(string strContent)
        {
            Console.WriteLine("normal" + strContent);
        }
 
        static void Main(string[] args)
        {
            AAA aaa = new AAA();
            aaa.print += aaa.DelegatePrintAAA1;
            aaa.print += aaa.DelegatePrintAAA2;
            //aaa.print = aaa.DelegatePrintAAA3; error 발생
            //aaa.print("111111"); error 발생
            aaa.totalOutput();
 
            aaa.print -= aaa.DelegatePrintAAA1;
            aaa.totalOutput();
        }
    }
}
 
 
 

이 예제에서 확인해봤을때 할당 연산이나 직접호출은 불가능합니다.

반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] 제네릭  (0) 2019.10.19
[C#] 인덱서(Indexer)  (0) 2019.10.18
[C#] delegate  (0) 2019.10.16
[C#] Event  (0) 2019.10.15
[C#] yield  (0) 2019.10.14
반응형

특정 매개 변수와 반환 형식을 가진 함수에 대한 참조를 나타내는 형식을 말합니다.
delegate는 함수에 변수나 클래스를 인수로 전달하는 것과 같이 함수를 인수로 전달하는데 사용됩니다.
접근 가능한 클래스 또는 delegate형식과 일치하는 구조를 가진 모든 메서드는 대리자로 할당할 수 있습니다.
함수는 정적 함수거나 인스턴스 함수일 수 있습니다.

속성
- C++ 함수 포인터와 유사하지만 C++ 함수 포인터와 달리 어느 클래스 함수에서도 쉽게 할당 가능합니다.
- delegate는 함수 매개 변수로 전달이 가능합니다.
- delegate를 통해 콜백 함수를 정의할 수 있습니다.
- 여러 delegate를 연결 할 수 있습니다.

형식
public delegate 반환타입 함수명(매개 변수);
ex) public delegate void print(string strContent)


예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
 
    class Program
    {
        public delegate void Print(string strContent);
        static void DelegatePrint(string strContent)
        {
            Console.WriteLine(strContent);
        }
        
        static void Main(string[] args)
        {
            Print print = DelegatePrint;
 
            print("output1");
        }
    }
}
 
 



이렇게 간단하게 연결해서 사용할 수 있다.

1. 콜백함수
또한 매개변수로 전달하여 함수내에서 delegate를 호출할 수도 있습니다.
이렇게되면 동일한 함수안에 함수를 손쉽게 넣을 수 있게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
 
    class Program
    {
        public delegate void Print(string strContent);
        static void DelegatePrint(string strContent)
        {
            Console.WriteLine(strContent);
        }
 
        static void Callback(Print callbackprint)
        {
            callbackprint("output2");
        }
        
        static void Main(string[] args)
        {
            Print print = DelegatePrint;
            // delegate를 매개변수로 넣습니다.
            Callback(print);
        }
    }
}
 
 



2. 멀티캐스트
대리자는 호출 시 둘 이상의 메서드를 호출할 수 있습니다.
더 추가하려는 경우 더하기 또는 더하기 대입 연산자('+' 또는 '+=')를 사용할 수 있으며,
추가된 메서드를 제거하기위해서는 빼기 또는 빼기 대입연산자('-' 또는 '-=')를 사용할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    class AAA
    {
        public void DelegatePrintAAA1(string strContent)
        {
            Console.WriteLine("AAA1" + strContent);
        }
        public void DelegatePrintAAA2(string strContent)
        {
            Console.WriteLine("AAA2" + strContent);
        }
    }
    class Program
    {
        public delegate void Print(string strContent);
        static void DelegatePrint(string strContent)
        {
            Console.WriteLine("normal" + strContent);
        }
        
        static void Main(string[] args)
        {
            AAA aaa = new AAA();
            Print print = new Print(DelegatePrint);
            print += aaa.DelegatePrintAAA1;
            print += aaa.DelegatePrintAAA2;
            print("++");
 
            print -= aaa.DelegatePrintAAA1;
            print -= aaa.DelegatePrintAAA2;
            print("--");
        }
    }
}
 
 

3. 범용성
제너릭 <T>를 이용해서 어떤 변수형에 상관없이 구현할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication1
{
    delegate T calcDelegate<T>(T num1, T num2);
    
    class Program
    {
        static int addint(int num1, int num2)
        {
            return num1 + num2;
        }
 
        static float addfloat(float num1, float num2)
        {
            return num1 + num2;
        }
 
        public static void Calc<T>(T num1, T num2, calcDelegate<T> calc)
        {
            Console.WriteLine(calc(num1, num2));
        }
 
        static void Main(string[] args)
        {
            calcDelegate<int> addint1 = new calcDelegate<int>(addint);
            calcDelegate<float> addfloat2 = new calcDelegate<float>(addfloat);
 
            Calc(89, addint1);
            Calc(9.7f, 10.8f, addfloat2);
        }
    }
}
 
s
반응형

'개발공부 > C#' 카테고리의 다른 글

[C#] 인덱서(Indexer)  (0) 2019.10.18
[C#] 이벤트(event) & 델리게이트(delegate)  (0) 2019.10.17
[C#] Event  (0) 2019.10.15
[C#] yield  (0) 2019.10.14
[C#] 반복문  (0) 2019.10.13

+ Recent posts