Collection, Interface, Delegate

1. Collection
서로 밀접하게 관련된 데이터를 그룹화하여 좀 더 효율적으로 처리할 수 있게 한 특수한 클래스 혹은 구조체이다.


2. Collection과 Interface
모든 닷넷 컬렉션은 ICollection<T> 인터페이스는 구현한다.
IList<T> 인터페이스는 인덱스를 사용하여 요소에 개별적으로 접근할 수 있는 컬렉션을 정의한다.
-T this [int index] { get; set; } //지정한 인덱스에 있는 요소를 가져오거나 설정
-int IndexOf(T item) //IList에서 특정 항목의 인덱스를 확인
-void Insert(int index, T item) //항목을 IList의 지정한 인덱스에 삽입
-void RemoveAt(int index) //지정한 인덱스에서 IList 항목을 제거


3. Collection과 Method와 Delegate
// Person 클래스
public class Person
{
private readonly string _name;


public string Name
{
get { return _name; }
}


private readonly int _age;


public int Age
{
get { return _age; }
}


public Person(string name, int age)
{
_name = name;
_age = age;
}


public override string ToString()
{
return string.Format(“이름 : {0}\t나이 : {1}”, _name, _age);
}
}


// List<T> 컬렉션에 Person 객체를 담는다
private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));
}


// aList에 포함된 세 사람이 모두 10세 이상인지를 확인한다 => 둘리와 고길동만 만족함
private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));


bool result = true;
foreach (Person p in aList)
{
if (p.Age < 10)
{
result = false;
break;
}
}
}


// aList에 포함된 세 사람이 모두 이름이 두 글자인지를 확인한다 => 둘리만 만족함
private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));


bool result = true;
foreach (Person p in aList)
{
if (p.Name.Length != 2)
{
result = false;
break;
}
}
}


// 위의 두 코드가 나이가 10세이상인지 또는 이름이 두 글자인지 조건을 만족하는지를 확인하는 부분이 반복
// List<T> 컬렉션의 TrueForAll 메소드는 조건을 만족하는 메소드가 존재한다면 true반환
public delegate bool Predicate<T>(T item);


public class List<T> : …
{


public bool TrueForAll(Predicate<T> match)
{
bool result = true;
foreach (T item in this)
{
if (match(item) == false)
{
result = false;
break;
}
}
}
}


private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));


// 10살 이상인지를 검사
bool result1 = aList.TrueForAll(IsGreaterThanTen);


// 무명 대리자를 사용하여 이름이 두 글자인지 검사
bool result2 = aList.TrueForAll(delegate(Person p)
{ return p.Name.Length == 2; });
}


private static bool IsGreaterThanTen(Person p)
{
return p.Age >= 10;
}

4. List<T> 컬랙션 클래스의 메소드와 헬퍼 대리자


public List<TOutput> ConvertAll<TOutput> (Converter<T, TOutput> converter)
-리스트 객체의 각 원소를 TOutput 형으로 변환하여 리스트로 반환


public bool Exists(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 원소가 있는지 여부를 반환


public T Find(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 첫번째 원소를 반환


public List<T> FindAll(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 모든 원소를 리스트로 반환


public int FindIndex(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 첫번째 원소의 인덱스를 반환


public int FindLastIndex(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 마지막 원소의 인덱스를 반환


public void ForEach(Action<T> action)
-리스트에 있는 모든 원소에 대해 action을 수행


public bool TrueForAll(Predicate<T> match)
-리스트에 있는 모든 원소가 match 조건을 만족하는 지 여부를 반환


<<대리자(Delegate)>>


public delegate void Action<T>(T object)
-T 형의 매개변수를 하나 받고 반환값이 없는 메소드


public delegate TOutput Converter<TInput, TOutput>(TInput input)
-TInput 형의 매개변수를 받고 이를 TOutput 형으로 변환하여 반환하는 메소드


public delegate bool Predicate<T>(T object)
-T 형의 매개변수를 받아 그것이 특정 조건을 만족하는지를 반환하는 메소드


public delegate int Comparison<T>(T x, T y)
-x, y 두 객체를 비교하는 메소드로 x가 y보다 작으면 음수, 같으면 0, 크면 양수를 반환하는 메소드


5. List<T>의 Sort 메소드
public void Sort()
public void Sort(Comparison<T> comparison)
public void Sort(IComparer<T> comparer)
public void Sort(int index, int count, IComparer<T> comparer)


-public void Sort()
즉, 매개변수가 없는 Sort 메서드(void Sort())는 List<T>의 원소인 객체와 계약을 맺었는데,
그 계약의 내용은 List<T>의 원소인 객체는 int CompareTo(T other)와 같은 메서드를 가지고 있다는 것입니다.
따라서 실제 List<T>의 원소의 객체가 무엇이든지 간에 Sort 메서드는 그 객체의 CompareTo 메서드를 호출하면 정렬을 수행할 수 있다.
List<T>의 원소인 객체는 int CompareTo(T other)를 구현하여야 한다.
즉, Person이 int CompareTo(Person other) 메소드에 이름 순으로 구현하여야 계약이 성립한다.


public class Person : IComparable<Person>
{
….

// Sort
public int CompareTo(Person other)
{
return this.Name.CompareTo(other.Name);
}
}


private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));


// 이름순으로 정렬
aList.Sort();
}

-public void Sort(Comparison<T> comparison)
이번에는 이름이 아니라 나이 순으로 정렬을 하는 경우,
int CompareTo(Person other) 내부 구현을 이름이 아니라 나이를 기준으로 정렬하도록 수정한다.
이 경우 동적으로 Sort를 다르게 할수없는 문제가 있으므로,
List<T>의 원소를 비교 가능한 객체라고 전제 하는 것이 아니라,
Sort 메서드의 매개 변수로 아예 List<T>의 원소들을 비교하는 메서드를 전달하는 것입니다.

public delegate int Comparison<T>(T x, T y)
Comparison 대리자의 의미는 x가 y보다 작으면 음수, 같으면 0, 크면 양수를 반환한다는 것이다.

public static int ComparePersonByName(Person x, Person y)
{
return x.Name.CompareTo(y.Name);
}

public static int ComparePersonByAge(Person x, Person y)
{
return x.Age.CompareTo(y.Age);
}


private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));


// 이름순으로 정렬
aList.Sort(ComparePersonByName);
// 나이순으로 정렬
aList.Sort(ComparePersonByAge);
}

-public void Sort(IComparer<T> comparer)
Sort가 IComparer<T> 인터페이스를 매개변수로 받아 처리할 수 있다.
int Compare(T x, T y)

public class PersonNameComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Name.CompareTo(y.Name);
}
}


public class PersonAgeComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Age.CompareTo(y.Age);
}
}


private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));


// 이름순으로 정렬
aList.Sort(new PersonNameComparer());
// 나이순으로 정렬
aList.Sort(new PersonAgeComparer());


foreach(Person p in aList)
Console.WriteLine(p); // Person의 ToString 호출
}

Generic List Class

<<List<T> 컬랙션 클래스의 메소드>>

public List<TOutput> ConvertAll<TOutput> (Converter<T, TOutput> converter)
-리스트 객체의 각 원소를 TOutput 형으로 변환하여 리스트로 반환

public bool Exists(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 원소가 있는지 여부를 반환

public T Find(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 첫번째 원소를 반환

public List<T> FindAll(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 모든 원소를 리스트로 반환

public int FindIndex(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 첫번째 원소의 인덱스를 반환

public int FindLastIndex(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 마지막 원소의 인덱스를 반환

public void ForEach(Action<T> action)
-리스트에 있는 모든 원소에 대해 action을 수행

public bool TrueForAll(Predicate<T> match)
-리스트에 있는 모든 원소가 match 조건을 만족하는 지 여부를 반환

<<대리자(Delegate)>>

public delegate void Action<T>(T object)
-T 형의 매개변수를 하나 받고 반환값이 없는 메소드

public delegate TOutput Converter<TInput, TOutput>(TInput input)
-TInput 형의 매개변수를 받고 이를 TOutput 형으로 변환하여 반환하는 메소드

public delegate bool Predicate<T>(T object)
-T 형의 매개변수를 받아 그것이 특정 조건을 만족하는지를 반환하는 메소드

public delegate int Comparison<T>(T x, T y)
-x, y 두 객체를 비교하는 메소드로 x가 y보다 작으면 음수, 같으면 0, 크면 양수를 반환하는 메소드

Parameter Passing

static void ChangeArray1(int[] arr) // copy of reference가 전달
 {
      arr[0] = 888;       // 원본 배열의 첫번째 값은 888로 변경
      for (int i = 0; i < arr.Length; i++ )        
                Console.WriteLine(“inside arr[{0}]={1}”, i, arr[i]);
     
      arr = new int[5] { -3, -1, -2, -3, -4 }; // local 변수 재지정
      for (int i = 0; i < arr.Length; i++ )
               Console.WriteLine(“inside2 arr[{0}]={1}”, i, arr[i]);
 }

static void ChangeArray2(ref int[] arr)
{
     arr[0] = 888;       // 원본 배열의 첫번째 값은 888로 변경        
     for (int i = 0; i < arr.Length; i++ )            
              Console.WriteLine(“inside arr[{0}]={1}”, i, arr[i]);
     
     arr = new int[5] { -3, -1, -2, -3, -4 }; // 원본 배열이 변경
     for (int i = 0; i < arr.Length; i++ )
             Console.WriteLine(“inside2 arr[{0}]={1}”, i, arr[i]);
}
 
static void Main()
 {
            int[] myArray = { 1, 4, 5 };            
            Console.WriteLine(“myArray[0]={0}”, myArray[0]);
            ChangeArray1(myArray);
            for (int j = 0; j < myArray.Length; j++ )
                Console.WriteLine(“myArray[{0}]={1}”, j, myArray[j]);

            myArray = new int[3] { 1, 4, 5 };
            Console.WriteLine(“myArray[0]={0}”, myArray[0]);
            ChangeArray2(ref myArray);
            for (int j = 0; j < myArray.Length; j++ )
                 Console.WriteLine(“myArray[{0}]={1}”, j, myArray[j]);
}

출력결과:
myArray[0]=1
inside arr[0]=888
inside arr[1]=4
inside
arr[2]=5
inside2 arr[0]=-3
inside2 arr[1]=-1
inside2
arr[2]=-2
inside2 arr[3]=-3
inside2
arr[4]=-4
myArray[0]=888
myArray[1]=4
myArray[2]=5

myArray[0]=1
inside
arr[0]=888
inside arr[1]=4
inside arr[2]=5
inside2 arr[0]=-3
inside2
arr[1]=-1
inside2 arr[2]=-2
inside2 arr[3]=-3
inside2
arr[4]=-4
myArray[0]=-3
myArray[1]=-1
myArray[2]=-2
myArray[3]=-3
myArray[4]=-4

== operator

       static void Main(string[] args)
        {
            // 값형식과 참조형식
            int val1 = 5;
            int val2 = 10;
            if (val1 == val2) // false (val1과 val2는 값이 다름)
                Console.WriteLine(“val1 == val2”);
            else
                Console.WriteLine(“val1 != val2”);
            object val3 = val1;
            object val4 = val1;
            if (val3 == val4) // false (val3와  val4는 같은 곳을 참조하지 않음)
                Console.WriteLine(“val3 == val4”);
            else
                Console.WriteLine(“val3 != val4”);

            int val5 = (int)val3;
            int val6 = (int)val4;
            if (val5 == val6) // true (val5와 val6은 같은 값을 가짐)
                Console.WriteLine(“val5 == val6”);
            else
                Console.WriteLine(“val5 != val6”);

            Point pos1 = new Point(val1, val2);
            Point pos2 = new Point(val1, val2);
            if (pos1 == pos2) // false (만약 Point Class가 ==연산자와  != 연산자와 Equals와 GetHashCode를 구현하지 않았다면 같은 곳을 참조하고 있지 않음) true (만약 Point Class가 데이터의 내용이 같은지를 판별하는 ==연산자와 !=연산자와 Equals와 GetHashCode를 구현했다면)
                Console.WriteLine(“pos1 == pos2”);
            else
                Console.WriteLine(“pos1 != pos2”);
            if (pos1.X == pos2.X) // true
                Console.WriteLine(“pos1.X == pos2.X”);
            else
                Console.WriteLine(“pos1.X != pos2.X”);
            if (pos1.Y == pos2.Y) // true
                Console.WriteLine(“pos1.Y == pos2.Y”);
            else
                Console.WriteLine(“pos1.Y != pos2.Y”);

            Point pos3 = pos1;
            Point pos4 = pos1;
            if (pos3 == pos4) // true (pos3와 pos4는 같은 곳을 참조하고 있음)
                Console.WriteLine(“pos3 == pos4”);
            else
                Console.WriteLine(“pos3 != pos4”);

            object pos5 = pos3;
            object pos6 = pos4;
            if (pos5 == pos6) // true (pos5와 pos6는 같은 곳을 참조하고 있음)
                Console.WriteLine(“pos5 == pos6”);
            else
                Console.WriteLine(“pos5 != pos6”);

            Point pos7 = (Point)pos6;
            if (pos1 == pos7) // true (pos1, pos3, pos4, pos6, pos7는 같은 곳을 참조하고 있음)
                Console.WriteLine(“pos1 == pos7”);
            else
                Console.WriteLine(“pos1 != pos7”);
            if (pos2 == pos7) // false (만약 Point Class가 ==연산자와 != 연산자와 Equals와 GetHashCode를 구현하지 않았다면 같은 곳을 참조하고 있지 않음) true (만약 Point Class가 데이터의 내용이 같은지를 판별하는 ==연산자와 !=연산자와 Equals와 GetHashCode를 구현했다면)
                Console.WriteLine(“pos2 == pos7”);
            else
                Console.WriteLine(“pos2 != pos7”);

C# operator== vs. Equals

http://msdn.microsoft.com/en-us/library/ms173147.aspx

// Operator Overloading
if (x == y) { // 컴파일시 x와 y가 동일한지 확인

// 참조형일 경우
object x = “hello”;
object y = ‘h’ + “ello”; // ensure it’s a different reference
if (x == y) { // 결과 => FALSE
if (x.Equals(y)) { // 결과 => TRUE

// string 형(참조형이긴 하지만)일 경우
// Equals와 equality operators (== and !=) 을 구현하여 string 객체의 값이 동일한지 확인
string x1 = “hello”;
string y1 = ‘h’ + “ello”; // ensure it’s a different reference
if (x1 == y1) { // 결과 => TRUE
if (x1.Equals(y1)) { // 결과 => TRUE

Interface

Interface (인터페이스)
http://dis.dankook.ac.kr/lectures/hci09/entry/Interface

IEnumerable & IEnumerator Interface
-IEnumerable 인터페이스는 foreach를 사용하여 컬랙션을 반복하는 것을 지원하기 위해 구현하여 사용한다.
http://dis.dankook.ac.kr/lectures/hci11/entry/IEnumerable
http://dis.dankook.ac.kr/lectures/hci09/entry/Enumerator

IEquatable Interface
-IEquatable 인터페이스는 두 객체간에 서로 내부 내용이 같은 지 (예: if(a == b))를 비교하기 위해 구현하여 사용한다.
http://dis.dankook.ac.kr/lectures/hci11/entry/IEquatable
http://dis.dankook.ac.kr/lectures/hci10/72
http://dis.dankook.ac.kr/lectures/hci09/entry/Equals

IComparable Interface
-IComparable 인터페이스는 개체에 대한 기본 정렬(sort) 순서를 지정해주기 위해 구현하여 사용한다. 해당 개체를 배열이나 컬랙션에서 정렬하는데 필요하다.
http://dis.dankook.ac.kr/lectures/hci11/entry/IComparable

Method Overloading vs. Method Overriding

http://dis.dankook.ac.kr/lectures/hci10/entry/Method-Overloading-vs-Method-Overriding

Method Overloading: 동일한 함수명에 매개변수가 다른 함수를 둘 이상 정의하는 것으로, 동일한 함수 기능을 수행하지만 다른 매개변수의 경우를 처리할 때 사용

Method Overriding: 상속받은 파생 클래스에서 동일한 함수명에 동일한 매개변수로 정의하여 함수를 재정의하는 것으로 상속되어진 함수의 기능을 변경해서 재사용하고 싶을 때 사용

    class Point : IEquatable<Point>, IComparable<Point>
    {
        // static member field
        protected static int count = 0;

        // instance member field
        protected int x, y;


        // property
        public int X
        {
            get { return this.x; }
            set { this.x = value; }
        }


        public int Y
        {
            get { return this.y; }
            set { this.y = value; }
        }


        public static int Count
        {
            get { return count; }   // error: this.count 는 사용할 수 없음
        }


        // constructor & destructor
      public Point() : this(0, 0) { }
      public Point(int x, int y) { this.x = x; this.y = y; count++; }
        ~Point() { count–; }


        // method
      public void SetPosition(int x, int y) { this.x = x; this.y = y; }
      public void Move(int x, int y) { this.x += x; this.y += y; }


      // ToString method override
      public override string ToString() { return (String.Format(“({0}, {1})”, x, y)); }
      // virtual method
      public virtual void Print() { Console.WriteLine(“X={0} Y={1}”, x, y); }
       
        // static method
        public static int GetCount() { return count; }
                                 
      // operator++ overload
      public static Point operator++(Point p) { ++p.x; ++p.y; return p; }            
      // operator== overload
      public static bool operator==(Point p1, Point p2) { return p1.Equals(p2); }    
      // operator!= overload        
      public static bool operator!=(Point p1, Point p2) { return !p1.Equals(p2); }    
      public override int GetHashCode() { return x ^ y; }
      public override bool Equals(object obj)
      {
            if (!(obj is Point))
                return false;
            return Equals((Point)obj);
      }
 
        // IEquatable
        public bool Equals(Point other)
        {
            if (this.x == other.x && this.y == other.y)
                return true;
            return false;
        }


        // IComparable
        public int CompareTo(Point other)
        {
            if (this.x > other.x)
            {
                return 1;
            }
            else if (this.x < other.x)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }
    }






    class Point3D : Point, IEquatable<Point3D>
    {
        // instance member field
        protected int z;


        // property
        public int Z
        {
            get { return this.z; }
            set { this.z = value; }
        }


        // constructor & destructor
      public Point3D() : this(0, 0, 0) { }
      public Point3D(int x, int y, int z) : base(x, y) { this.z = z; }
        ~Point3D() { }


      public void SetPosition(int x, int y, int z) { base.SetPosition(x, y); this.z = z; }
      public void Move(int x, int y, int z) { base.Move(x, y); this.z += z; }


      // override ToString method
      public override string ToString() { return (String.Format(“({0}, {1}, {2})”, x, y, z)); }
      // overrided method
      public override void Print() { Console.WriteLine(“X={0} Y={1} Z={2}”, x, y, z); }  
      // operator++ overload
      public static Point3D operator++(Point3D p) { ++p.x; ++p.y; ++p.z; return p; }      
      // operator== overload
      public static bool operator ==(Point3D p1, Point3D p2) { return p1.Equals(p2); }    
      // operator!= overload  
      public static bool operator !=(Point3D p1, Point3D p2) { return !p1.Equals(p2); }  
      
public override int GetHashCode() { return x ^ y ^ z; }
      public override bool Equals(object obj)
      {
            if (!(obj is Point3D))
                return false;
            return Equals((Point3D)obj);
      }


        // IEquatable
        public bool Equals(Point3D other)
        {
            if (this.x == other.x && this.y == other.y && this.z == other.z)
                return true;
            return false;
        }
    }




    class PointTest
    {
      // pass-by-value (value type)
      static void Swap(int p1, int p2)            
        {
            int p;
            p = p1;
            p1 = p2;
            p2 = p;
        }


      // pass-by-reference (value type)
      static void Swap(ref int p1, ref int p2)
        {
            int p;
            p = p1;
            p1 = p2;
            p2 = p;
        }


      // pass-by-value (reference type)
      static void Swap(int[] p1, int[] p2)        
        {
            int[] p;
            p = p1;
            p1 = p2;
            p2 = p;
        }


      // pass-by-value (reference type)
      static void Swap(ref int[] p1, ref int[] p2)        
        {
            int[] p;
            p = p1;
            p1 = p2;
            p2 = p;
        }


      static void Swap(ref Point p1, ref Point p2)
        {
            Point p;
            p = p1;
            p1 = p2;
            p2 = p;
        }


      static void Swap(ref Point3D p1, ref Point3D p2)
        {
            Point3D p;
            p = p1;
            p1 = p2;
            p2 = p;
        }


        static void Main(string[] args)
        {
            // value type: pass-by-value/pass-by-reference
            int i = 5, j = 10;
            Console.WriteLine(“Before: i={0}, j={1}”, i, j);


          Swap(i, j);
            Console.WriteLine(“After integer pass-by-value swap: i={0}, j={1}”, i, j);


          Swap(ref i, ref j);
            Console.WriteLine(“After integer pass-by-reference Swap: i={0}, j={1}”, i, j);


            // reference type: pass-by-value/pass-by-reference
            int[] arr1 = { 1, 2, 3 };
            int[] arr2 = { 4, 5, 6, 7, 8 };
            Console.WriteLine(“Before array pass-by-value swap: “);
            Console.Write(“arr1: “);
            foreach (int a in arr1)
                Console.Write(“{0} “, a);
            Console.WriteLine();
            Console.Write(“arr2: “);
            foreach (int a in arr2)
                Console.Write(“{0} “, a);
            Console.WriteLine();


          Swap(arr1, arr2);
            Console.WriteLine(“After array pass-by-value swap: “);
            Console.Write(“arr1: “);
            foreach (int a in arr1)
                Console.Write(“{0} “, a);
            Console.WriteLine();
            Console.Write(“arr2: “);
            foreach (int a in arr2)
                Console.Write(“{0} “, a);
            Console.WriteLine();


          Swap(ref arr1, ref arr2);
            Console.WriteLine(“After array pass-by-reference swap: “);
            Console.Write(“arr1: “);
            foreach (int a in arr1)
                Console.Write(“{0} “, a);
            Console.WriteLine();
            Console.Write(“arr2: “);
            foreach (int a in arr2)
                Console.Write(“{0} “, a);
            Console.WriteLine();


            Console.Write(“p1: “);
            Point p1 = new Point();
            Console.Write(“p2: “);
            Point p2 = new Point();


            // Point
            p1.SetPosition(10, 10);  // 변수 값 지정
            Console.Write(“p1 SetPosition: “);
            p1.Print();    // 현재 좌표 출력
            p1.Move(20, 50);  // 좌표 변경 (점의 위치 이동)
            Console.Write(“p1 Move: “);
            p1.Print();    // 현재 좌표 출력
            Console.WriteLine(“p1=” + p1);


            p2.SetPosition(20, 30); // 변수 값 지정
            Console.Write(“p2 SetPosition: “);
            p2.Print();    // 현재 좌표 출력


            //포인터 객체 교환함수 호출
            Console.WriteLine(“\nSwap”);
          Swap(ref p1, ref p2);
            Console.WriteLine(“p1: {0}”, p1);
            Console.WriteLine(“p2: {0}”, p2);


            Console.WriteLine();
            Console.WriteLine(“p1.m_nX={0}, p1.m_nY={1}, Point.GetCount()={2}”, p1.X, p1.Y, Point.Count);
            Console.WriteLine(“p2.m_nX={0}, p2.m_nY={1}, Point.GetCount()={2}”, p2.X, p2.Y, Point.Count);


            // Point3D
            Console.Write(“p3: “);
            Point3D p3 = new Point3D();
            Console.Write(“p4: “);
            Point3D p4 = new Point3D();


            Console.WriteLine();
          p3.SetPosition(10, 20);
            Console.Write(“p3 SetPosition: “);
            p3.Print();   // 현재 좌표 출력
          p3.SetPosition(30, 40, 50);
            Console.Write(“p3 SetPosition: “);
            p3.Print();   // 현재 좌표 출력
          ++p3;
            Console.Write(“++p3: “);
            p3.Print();   // 현재 좌표 출력
          p3.Move(20, 30, 40);   // 좌표 변경 (점의 위치 이동)
            Console.Write(“p3 Move: “);
            p3.Print();   // 현재 좌표 출력
          p3.Move(10, 10);   // 좌표 변경 (점의 위치 이동)
            Console.Write(“p3 Move: “);
          Console.WriteLine(p3); // p3는 Point클래스의 ToString이 호출


            Console.WriteLine();
            p4.SetPosition(100, 200, 300);
            Console.Write(“p4 SetPosition: “);
            p4.Print();   // 현재 좌표 출력
            p4.Move(10, 10, 10);   // 좌표 변경 (점의 위치 이동)
            Console.Write(“p4 Move: “);
            p4.Print();   // 현재 좌표 출력


            //포인터 객체 교환함수 호출
            Console.WriteLine(“\nSwap”);
          Swap(ref p3, ref p4);
            Console.WriteLine(“p1: {0}”, p3);
            Console.WriteLine(“p2: {0}”, p4);


            Console.WriteLine();
            Console.WriteLine(“p3.m_nX={0}, p3.m_nY={1}, p3.m_nZ={2}, Point.GetCount()={3}”, p3.X, p3.Y, p3.Z, Point.GetCount());
            Console.WriteLine(“p4.m_nX={0}, p4.m_nY={1}, p4.m_nZ={2}, Point.count={3}”, p4.X, p4.Y, p4.Z, Point.Count);


          if (p3 == p4)
                Console.WriteLine(“p3 == p4”);
          if (p3 != p4)
                Console.WriteLine(“p3 != p4”);


            Console.Write(“p5: “);
          Point p5 = p3;
          p5.Print();   // 현재 좌표 출력 p5는 Point3D – polymorphism
            Console.Write(“p6: “);
          Point p6 = new Point3D(110, 210, 310); // p6도 Point3D
          p6.Print();   // Point3D의 Print가 호출 (late binding) – polymorphism
            Point3D p7 = (Point3D)p5;
          Console.WriteLine(p7);   // p7는 Point3D클래스의 ToString이 호출
          if (p7 == p5)
                Console.WriteLine(“p7 == p5”);
          if (p7 == p6)
                Console.WriteLine(“p7 == p6”);
        }
    }