반응형

제너릭 프로그래밍


장점은 하단에..



제네릭 메소드와 클래스 예제

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
using System;
 
namespace GenericEx
{
    class ClassA
    {
        public static void CopyArray(int[] src, int[] target)
        {
            for (int i = 0; i < src.Length; ++i)
            {
                target[i] = src[i];
            }
        }
        
        public static void CopyArray(string[] src, string[] target)
        {
            for (int i = 0; i < src.Length; ++i)
            {
                target[i] = src[i];
            }
        }
        
        // 제네릭 메소드
        public static void GenericCopyArray<T>(T[] src, T[] target)
        {
            for (int i = 0; i < src.Length; ++i)
            {
                target[i] = src[i];
            }
        }
    }
    
    // 제네릭 클래스
    class GenericClassA<T>
    {
        public static void GenericCopyArray(T[] src, T[] target)
        {
            for (int i = 0; i < src.Length; ++i)
            {
                target[i] = src[i];
            }
        }
    }
 
    class MainClass
    {
        public static void Main (string[] args)
        {
                int[] iSrc = { 12345 };
                int[] iTarget = new int[5];
                
                string[] strSrc = { "ab""cd""ef""gh""ij" };
                string[] strTarget = new string[5];
                
                ClassA.CopyArray(iSrc, iTarget);
                foreach (int i in iTarget)
                    Console.WriteLine(i);
                
                ClassA.CopyArray(strSrc, strTarget);
                foreach (string s in strTarget)
                    Console.WriteLine(s);
                
                float[] fSrc = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f };
                float[] fTarget = new float[5];
                
                // 제네릭 메소드의 활용
                ClassA.GenericCopyArray<float>(fSrc, fTarget);
                foreach (float f in fTarget)
                    Console.WriteLine(f);
                
                // 제네릭 클래스의 활용
                GenericClassA<float>.GenericCopyArray(fSrc, fTarget);
                foreach (float f in fTarget)
                    Console.WriteLine(f);
                
                Console.ReadKey();
        }
    }
}
cs

LinkedList<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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
using System;
using System.Text;
using System.Collections.Generic;
 
namespace LinkedListTEx
{
    class MainClass
    {
        private static void Display(LinkedList<string> words, string test)
        {
            Console.WriteLine(test);
            foreach (string word in words)
            {
                Console.Write(word + " ");
            }
            Console.WriteLine();
            Console.WriteLine();
        }
        
        private static void IndicateNode(LinkedListNode<string> node, string test)
        {
            Console.WriteLine(test);
            if (node.List == null)
            {
                Console.WriteLine("Node '{0}' is not in the list.\n",
                                  node.Value);
                return;
            }
            
            StringBuilder result = new StringBuilder("(" + node.Value + ")");
            LinkedListNode<string> nodeP = node.Previous;
            
            while (nodeP != null)
            {
                result.Insert(0, nodeP.Value + " ");
                nodeP = nodeP.Previous;
            }
            
            node = node.Next;
            while (node != null)
            {
                result.Append(" " + node.Value);
                node = node.Next;
            }
            
            Console.WriteLine(result);
            Console.WriteLine();
        }
 
        public static void Main (string[] args)
        {
            string[] words = { "유니티""C#으로""스크립팅""한다"};
 
            // 연결 리스트의 생성
            LinkedList<string> sentence = new LinkedList<string>(words);
 
            Display(sentence, "연결 리스트의 값은:");
            Console.WriteLine("sentence.Contains(\"유니티\") = {0}", sentence.Contains("유니티"));
 
            sentence.AddFirst("오늘은");
            Display(sentence, "Test 1: 리스트 앞에 '오늘은' 문자열 추가");
 
            LinkedListNode<string> mark1 = sentence.First;
            sentence.RemoveFirst();
            sentence.AddLast(mark1);
            Display(sentence, "Test 2: 마지막 단어를 끝으로 이동");
 
            sentence.RemoveLast();
            sentence.AddLast("오늘만");
            Display(sentence, "Test 3: 마지막 단어를 '오늘만' 으로 변경");
 
            mark1 = sentence.Last;
            sentence.RemoveLast();
            sentence.AddFirst(mark1);
            Display(sentence, "Test 4: 마지막 노드를 첫 노드로 이동");
            
            sentence.RemoveFirst();
            LinkedListNode<string> current = sentence.FindLast("C#으로");
            IndicateNode(current, "Test 5: '스크립팅'이라는 단어를 찾아 가리킨다 ");
            
            sentence.AddAfter(current, "자바스크립트로");
            sentence.AddAfter(current, "그리고");
            IndicateNode(current, "Test 6: '스크립팅' 단어 뒤에 단어 추가");
 
            current = sentence.Find("유니티");
            IndicateNode(current, "Test 7: '유니티' 노드를 가리킨다");
 
            sentence.AddBefore(current, "오늘과");
            sentence.AddBefore(current, "내일은");
            IndicateNode(current, "Test 8: '오늘과', '내일은' 단어를 '유니티' 노드 앞에 추가");
        }
    }
}
cs

List<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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System;
using System.Collections.Generic;
 
namespace ListTEx
{    
    public class Enemy {
        public string Name { get; set; }        
        public int Level { get; set; }
        public int HP { get; set; }
        public int Exp { get; set; }
                
        public void printEnemyInfo() {
            Console.WriteLine ("Name : {0} Level : {1} HP : {2} Exp : {3}", Name, Level, HP, Exp);
        }
    }
 
    class MainClass
    {
        public static List<Enemy> enemyList;
 
        public static void Main (string[] args)
        {
            enemyList = new List<Enemy>();
            // 추가
            enemyList.Add (new Enemy () { Name = "Slime", Level = 1, HP = 200, Exp = 30 });
            enemyList.Add (new Enemy () { Name = "Zombie", Level = 2, HP = 100, Exp = 50 });
            enemyList.Add (new Enemy () { Name = "Skeleton", Level = 3, HP = 120, Exp = 80 });
            enemyList.Add (new Enemy () { Name = "Bugbear", Level = 4, HP = 300, Exp = 150 });
 
            // 삽입
            enemyList.Insert (2new Enemy () { Name = "Bugbear", Level = 5, HP = 350, Exp = 180 });
 
            Console.WriteLine ("**********************");
            foreach (Enemy enemy in enemyList) {
                enemy.printEnemyInfo();
            }
 
            // 삭제
            enemyList.RemoveAt (2);
 
            // 검색 후 삭제
            Enemy bugBear = enemyList.Find (x => x.Name.Equals ("Bugbear"));
            enemyList.Remove (bugBear);
 
            Console.WriteLine ("**********************");
            foreach (Enemy enemy in enemyList) {
                enemy.printEnemyInfo();
            }
        }
    }
}
cs

Dictionary<TKey, TValue> 예제

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
using System;
using System.Collections.Generic;
 
namespace DictionaryTEx
{
    public class FileFormatTable {
        private Dictionary<stringstring> openWith;
        
        public FileFormatTable() {
            openWith = new Dictionary<stringstring>();
            
            // 추가
            openWith.Add("txt""notepad.exe");
            openWith.Add("bmp""paint.exe");
            openWith.Add("dib""paint.exe");
            openWith.Add("rtf""wordpad.exe");
            openWith.Add("odf""wordpad.exe");
            
            // 이미 할당 된 키일 경우 
            try
            {
                openWith.Add("txt""winword.exe");
            }
            catch
            {
                Console.WriteLine("An element with Key = \"txt\" already exists.");
            }
            
            // 제거
            openWith.Remove("odf");
        }
        
        public void printTable() {
            // 탐색
            foreach (KeyValuePair<stringstring> d in openWith)
                Console.WriteLine("Key = {0}, Value = {1}", d.Key, d.Value);
        }
    }
 
    class MainClass
    {
        public static void Main (string[] args)
        {
            FileFormatTable fileFormatTable = new FileFormatTable ();
            fileFormatTable.printTable ();
        }
    }
}
cs

Queue<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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System;
using System.Collections.Generic;
 
namespace QueueTEx
{
    public class Enemy {
        public string Name { get; set; }        
        public int Level { get; set; }
        public int HP { get; set; }
        public int Exp { get; set; }
        
        public void printEnemyInfo() {
            Console.WriteLine ("Name : {0} Level : {1} HP : {2} Exp : {3}", Name, Level, HP, Exp);
        }
    }
 
    class MainClass
    {
        public static Queue<Enemy> enemyQueue;
 
        public static void Main (string[] args)
        {
            enemyQueue = new Queue<Enemy>();
            // 추가
            enemyQueue.Enqueue (new Enemy () { Name = "Slime", Level = 1, HP = 200, Exp = 30 });
            enemyQueue.Enqueue (new Enemy () { Name = "Zombie", Level = 2, HP = 100, Exp = 50 });
            enemyQueue.Enqueue (new Enemy () { Name = "Skeleton", Level = 3, HP = 120, Exp = 80 });
            enemyQueue.Enqueue (new Enemy () { Name = "Bugbear", Level = 4, HP = 300, Exp = 150 });
            enemyQueue.Enqueue (new Enemy () { Name = "Bugbear", Level = 5, HP = 350, Exp = 180 });
            
            Console.WriteLine ("**********************");
            foreach (Enemy enemy in enemyQueue) {
                enemy.printEnemyInfo();
            }
            
            // 삭제
            Console.WriteLine ("********* Out *********");
            Enemy outEnemy = enemyQueue.Dequeue ();
            outEnemy.printEnemyInfo ();
 
            Console.WriteLine ("**********************");
            foreach (Enemy enemy in enemyQueue) {
                enemy.printEnemyInfo();
            }
 
            // 검색 후 삭제
            Console.WriteLine ("******** First *********");
            Enemy firstEnemy = enemyQueue.Peek();
            firstEnemy.printEnemyInfo ();
        }
    }
}
cs



Stack<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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System;
using System.Collections.Generic;
 
namespace StackTEx
{
    public class Enemy {
        public string Name { get; set; }        
        public int Level { get; set; }
        public int HP { get; set; }
        public int Exp { get; set; }
        
        public void printEnemyInfo() {
            Console.WriteLine ("Name : {0} Level : {1} HP : {2} Exp : {3}", Name, Level, HP, Exp);
        }
    }
 
    class MainClass
    {
        public static Stack<Enemy> enemyStack;
 
        public static void Main (string[] args)
        {
            enemyStack = new Stack<Enemy>();
            // 추가
            enemyStack.Push (new Enemy () { Name = "Slime", Level = 1, HP = 200, Exp = 30 });
            enemyStack.Push (new Enemy () { Name = "Zombie", Level = 2, HP = 100, Exp = 50 });
            enemyStack.Push (new Enemy () { Name = "Skeleton", Level = 3, HP = 120, Exp = 80 });
            enemyStack.Push (new Enemy () { Name = "Bugbear", Level = 4, HP = 300, Exp = 150 });
            enemyStack.Push (new Enemy () { Name = "Bugbear", Level = 5, HP = 350, Exp = 180 });
            
            Console.WriteLine ("**********************");
            foreach (Enemy enemy in enemyStack) {
                enemy.printEnemyInfo();
            }
            
            // 삭제
            Console.WriteLine ("********* Out *********");
            Enemy outEnemy = enemyStack.Pop ();
            outEnemy.printEnemyInfo ();
            
            Console.WriteLine ("**********************");
            foreach (Enemy enemy in enemyStack) {
                enemy.printEnemyInfo();
            }
            
            // 검색 후 삭제
            Console.WriteLine ("******** Last *********");
            Enemy lastEnemy = enemyStack.Peek();
            lastEnemy.printEnemyInfo ();
        }
    }
}
cs



출처: http://codepump.tistory.com/56 [CodePump.NET]








제네릭의 장점

 

제네릭을 사용하면 이전 버전의 공용 언어 런타임과 C# 언어에 적용되었던 제한 사항을 해결할 수 있습니다. 이전 버전에서는 유니버설 기본 형식인 Object와 형식 사이의 캐스팅을 통해 일반화를 수행했습니다. 제네릭 클래스를 만들면 컴파일 타임에 형식이 안전한 컬렉션을 만들 수 있습니다.

제네릭이 아닌 컬렉션 클래스를 사용하는 경우의 제한 사항을 보여 주는 예로는 .NET Framework 클래스 라이브러리에서 ArrayList 컬렉션 클래스를 사용하는 간단한 프로그램을 작성하는 경우를 들 수 있습니다. ArrayList는 참조나 값 형식을 저장하기 위해 수정하지 않고도 사용할 수 있는 매우 편리한 컬렉션 클래스입니다.

 

// The .NET Framework 1.1 way to create a list:
System.Collections.ArrayList list1 = new System.Collections.ArrayList();
list1.Add(3);
list1.Add(105);

System.Collections.ArrayList list2 = new System.Collections.ArrayList();
list2.Add("It is raining in Redmond.");
list2.Add("It is snowing in the mountains.");

 

그러나 이러한 편리함에는 상응하는 대가가 따릅니다. ArrayList에 추가되는 모든 참조나 값 형식은 Object에 암시적으로 업캐스팅됩니다. 항목이 값 형식이면 이를 목록에 추가할 때 boxing해야 하고 이를 검색할 때 unboxing해야 합니다. 캐스팅이나 boxing 및 unboxing 작업은 모두 성능을 저하시킵니다. 큰 컬렉션을 반복해야 하는 시나리오에서는 boxing과 unboxing의 영향을 결코 무시할 수 없습니다.

다른 제한 사항으로는 컴파일 타임에 형식을 검사할 수 없다는 점을 들 수 있습니다. ArrayList는 Object에 모든 항목을 캐스팅하므로 컴파일 타임에 클라이언트 코드가 다음과 같은 작업을 수행하지 못하도록 막을 수 없습니다.

 

System.Collections.ArrayList list = new System.Collections.ArrayList();
// Add an integer to the list.
list.Add(3);
// Add a string to the list. This will compile, but may cause an error later.
list.Add("It is raining in Redmond.");

int t = 0;
// This causes an InvalidCastException to be returned.
foreach (int x in list)
{
    t += x;
}

유형이 다른 컬렉션을 만드는 경우 규칙을 정확히 따르는 의도적인 선택일지라도 문자열과 ints를 단일 ArrayList에 결합하면 프로그래밍 오류가 발생할 확률이 더 커지고 이러한 오류는 런타임 이전에 발견할 수 없습니다.

버전 1.0 및 1.1의 C# 언어에서는 고유한 형식별 컬렉션을 작성하는 방법으로만 .NET Framework 기본 클래스 라이브러리 컬렉션 클래스에서 코드를 일반화하는 위험을 방지할 수 있었습니다. 물론 이러한 클래스는 여러 데이터 형식에 다시 사용할 수 없으므로 일반화의 이점이 사라지고 저장하려는 각 형식에 대해 클래스를 다시 작성해야만 합니다.

ArrayList 및 기타 유사한 클래스에 실제로 필요한 것은 클라이언트 코드에서 사용하려는 특정 데이터 형식을 인스턴스별로 지정할 수 있는 방법입니다. 이렇게 하면 T:System.Object로 업캐스팅할 필요가 없어지고 컴파일러에서 형식을 검사할 수도 있게 됩니다. 즉, ArrayList에는 형식 매개 변수가 필요합니다. 제네릭은 바로 이러한 요구 사항을 충족시킵니다. N:System.Collections.Generic 네임스페이스의 제네릭 List<(Of <(T>)>) 컬렉션에서는 컬렉션에 항목을 추가하는 동일한 작업을 다음과 같이 수행할 수 있습니다.

 

// The .NET Framework 2.0 way to create a list
List<int> list1 = new List<int>();

// No boxing, no casting:
list1.Add(3);

// Compile-time error:
// list1.Add("It is raining in Redmond.");




반응형

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

String 문자열(C# 프로그래밍 가이드)  (0) 2017.09.18
제네릭 Collection(컬렉션) 개체  (0) 2017.09.08
using 과 Dispose()  (0) 2017.07.19
확장메서드 public static class  (0) 2017.07.18
프로퍼티 value  (0) 2015.11.17

+ Recent posts