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; }
// override method
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); }public virtual void Sum(Point other) { x += other.X; y += other.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 virtual bool Equals(Point other)
{
if (object.ReferenceEquals(this, other)) // if reference is the same
return true;
return (this.x == other.x && this.y == other.y);
}
// 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 method
public override string ToString() { return (String.Format(“({0}, {1}, {2})”, x, y, z)); }
public override void Print() { Console.WriteLine(“X={0} Y={1} Z={2}”, x, y, z); }

public override void Sum(Point other)
{

if (other is Point3D)
Sum((Point3D)other);
else base.Sum(other);
}


// overload method
public void Sum(Point3D other) { x += other.X; y += other.Y; z += other.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);
}
public override bool Equals(Point other)
{
if (other is Point3D))return Equals((Point3D)other);

else

return base.Equals(other);

}

// IEquatable
public bool Equals(Point3D other)
{

if (object.ReferenceEquals(this, other))
return true;
return this.x == other.x && this.y == other.y && this.z == other.z;
}
// IComparable
public int CompareTo(Point3D other)
{
if (this == other)
{
return 0;
}
else if (this.x < other.x)
{
return -1;
}
else if ((this.x == other.x) && (this.y < other.y))
{

return -1;
}

else if ((this.x == other.x) && (this.y == other.y) && (this.z < other.z))
{

return -1;
}

else
{

return 1;
}
}

}

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); // i=5, j=10
Swap(i, j);
Console.WriteLine(“After Swap(i,j): i={0}, j={1}”, i, j); // i=5, j=10
Swap(ref i, ref j);
Console.WriteLine(“After Swap(ref i, ref j): i={0}, j={1}”, i, j); // i=10, j=5
// 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); // arr1: 1 2 3
Console.WriteLine();
Console.Write(“arr2: “);
foreach (int a in arr2) Console.Write(“{0} “, a); // arr2: 4 5 6 7 8
Console.WriteLine();
Swap(arr1, arr2);
Console.WriteLine(“After Swap(arr1, arr2): “);
Console.Write(“arr1: “);
foreach (int a in arr1) Console.Write(“{0} “, a); // arr1: 1 2 3
Console.WriteLine();
Console.Write(“arr2: “);
foreach (int a in arr2) Console.Write(“{0} “, a); // arr2: 4 5 6 7 8
Console.WriteLine();
Swap(ref arr1, ref arr2);
Console.WriteLine(“After Swap(ref arra1, ref arr2): “);
Console.Write(“arr1: “);
foreach (int a in arr1) Console.Write(“{0} “, a); // arr1: 4 5 6 7 8
Console.WriteLine();
Console.Write(“arr2: “);
foreach (int a in arr2) Console.Write(“{0} “, a); // arr2: 1 2 3
Console.WriteLine();
// Point
Console.Write(“p1: “);
Point p1 = new Point();
p1.Print(); // Point.Print() (0, 0)
Console.Write(“p2: “);
Point p2 = new Point();
p2.Print(); // Point.Print() (0, 0)
p1.SetPosition(10, 10); // Point.SetPosition(int, int)
Console.Write(“p1 SetPosition: “);
p1.Print(); // Point.Print() (10, 10)
p1.Move(20, 50); // Point.Move(int, int)
Console.Write(“p1 Move: “);
Console.WriteLine(“p1=” + p1); // Point.ToString() (30, 60)
p2.SetPosition(20, 30); // Point.SetPosition(int, int)
Console.Write(“p2 SetPosition: “);
p2.Print(); // Point.Print() (20, 30)
//포인터 객체 교환함수 호출
Console.WriteLine(“\nSwap”);
Swap(ref p1, ref p2);
Console.WriteLine(“p1: {0}”, p1); // Point.ToString() (20, 30)
Console.WriteLine(“p2: {0}”, p2); // Point.ToString() (30, 60)
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();
p3.Print(); // Point3D.Print() (0, 0, 0)
Console.Write(“p4: “);
Point3D p4 = new Point3D();
p4.Print(); // Point3D.Print() (0, 0, 0)
Console.WriteLine();
p3.SetPosition(10, 20); // Point3D.SetPosition(int,int)
Console.Write(“p3 SetPosition: “);
p3.Print(); // Point3D.Print() (10, 20, 0)
p3.SetPosition(30, 40, 50); // Point3D.SetPosition(int,int,int)
Console.Write(“p3 SetPosition: “);
p3.Print(); // Point3D.Print() (30, 40, 50)
++p3; // Point3D.operator++
Console.Write(“++p3: “);
p3.Print(); // Point3D.Print() (31, 41, 51)
p3.Move(20, 30, 40); // Point3D.Move(int,int,int)
Console.Write(“p3 Move: “);
p3.Print(); // Point3D.Print() (51, 71, 91)
p3.Move(10, 10); // Point3D.Move(int,int)
Console.Write(“p3 Move: “);
Console.WriteLine(p3); // Point3D.ToString() (61, 81, 91)
Console.WriteLine();
p4.SetPosition(100, 200, 300); // Point3D.SetPosition(int,int,int)
Console.Write(“p4 SetPosition: “);
p4.Print(); // Point3D.Print() (100, 200, 300)
p4.Move(10, 10, 10); // Point.Move(int, int,int)
Console.Write(“p4 Move: “);
p4.Print(); // Point3D.Print() (110, 210, 310)
//SUM
Console.WriteLine(“\nSUM”);
p3.Sum(p4); // Point3D.Sum(Point3D) (61+110, 81+210, 91+310)
p3.Print(); // Point3D.Print() (171, 291, 401)
//포인터 객체 교환함수 호출
Console.WriteLine(“\nSwap”);
Swap(ref p3, ref p4); // (171,291,401) <-> (110,210,310)
Console.WriteLine(“p1: {0}”, p3); // Point3D.ToString() (110,210,310)
Console.WriteLine(“p2: {0}”, p4); // Point3D.ToString() (171,291,401)
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”); // Point3D.operator==
if (p3 != p4) Console.WriteLine(“p3 != p4”); // Point3D.operator!=
Console.Write(“p5: “);
// polymorphism
Point p5 = p3; // upcasting – P5는 Point 타입인 Point3D 객체
p5.Print(); // Point3D.Print() (late binding) (110,210,310)
p5.SetPosition(10,20); // Point.SetPosition(int,int)
p5.Print(); // Point3D.Print() (late binding) (10,20,310)
((Point3D)p5).SetPosition(10,20,30); // downcasting – Point3D.SetPosition(int,int,int)

p5.Print(); // Point3D.Print() (late binding) (10,20,30)
Console.Write(“p6: “);
Point p6 = new Point3D(110, 210, 310); // upcasting – p6도 Point 타입인 Point3D 객체
p6.Print(); // Point3D.Print() (late binding) (110,210,310)
p5.Sum(p6); // Point3D.Sum(Point) (late binding) (10+110, 20+210, 30+310)
p5.Print(); // Point3D.Print() (late binding) (110,230,340)
p6.Print(); // Point3D.Print() (late binding) (110,210,310)
Point3D p7 = (Point3D)p5; // downcasting
Console.WriteLine(p7); // Point3D.ToString()
Point3D p8 = p5 as Point3D;
Console.WriteLine(p7); // Point3D.ToString()
if (p7 == p8) Console.WriteLine(“p7 == p8”); // p7 == p8
}
}

override vs new

namespace PersonTest
{
class Person
{
static int count = 0;   // static (class) variables

string name;    // instance variables
int age;        // instance variables

public string Name
{
get
{
return name;
}
set
{
name = value;
}
}

public int Age
{
get
{
return age;
}
set
{
age = value;
}
}

public Person() : this(“”, 0)
{
}

public Person(string name, int age)
{
count++;
this.name = name;
this.age = age;
}

public virtual void Print()    // instance methods
{
Console.WriteLine(“Person Name: {0} Age: {1}”, name, age);
}

public override string ToString()      // instance methods
{
return “Person Name: ” + name + ” Age: ” + age;
}

public static int GetCount() { return count; }  // static (class) methods
public static void PrintCount() { Console.WriteLine(“Person Count: ” + count); }  // static (class) methods
}
}

namespace PersonTest
{
class Student : Person
{
static int scount = 0; // static (class) variables
int id;
public int ID
{
get
{
return id;
}
set
{
id = value;
}
}

public Student() : this(“”, 0, 5208) // Student() => public Student : base()와 같은 의미, 생성자는 상속안됨
{
}

public Student(string name, int age, int id)
: base(name, age)
{
this.id = id;
scount++;
}

public void BasePrint()
{
base.Print();
}

public override void Print() // instance methods
{
Console.WriteLine(“Student Name: {0} Age: {1} Id: {2}”, Name, Age, ID);
}

public override string ToString()  // instance methods
{
return “Student Name: ” + Name + ” Age: ” + Age + ” Id: ” + ID;
}

// Person 클래스의 GetCount & PrintCount와 동일한 이름이므로, Student 감춤. new 키워드를 사용하여 새로정의함.
public static new int GetCount() { return scount; } // static (class) methods
public static new void PrintCount() { Console.WriteLine(“Student Count: ” + scount); }  // static (class) methods
}
}

namespace PersonTest
{
class Program
{
static void Main(string[] args)
{
Person p1 = new Student(“Kyoung”, 22, 1207); // up casting
p1.Age = 30;
p1.Print(); // dynamic binding Student Name: Kyoung Age: 30 ID: 1207
//p1.BasePrint(); // cannot call Student method due to Person
//p1.PrintCount(); // cannot call static method with instance name
Person.PrintCount(); // calls Person.PrintCount() 1
Student.PrintCount(); // calls Student.PrintCount() 1

Student s1 = (Student)p1; // down casting
s1.Name = “HCI”;
s1.Age = 2;
s1.ID = 2016;
s1.Print(); // Student Name: HCI Age: 2 ID: 2016
s1.BasePrint(); // Person Name: HCI Age: 2
Person.PrintCount(); // calls Person.PrintCount() 1
Student.PrintCount(); // calls Student.PrintCount() 1

Student s2 = new Student(“Shin”, 20, 1207);
s2.Print(); // Student Name: Shin Age: 20 ID: 1207
s2.BasePrint(); // Person Name: Shin Age: 20
Person.PrintCount(); // calls Person.PrintCount() 2
Student.PrintCount(); // calls Student.PrintCount() 2

Person p2 = new Person(“Park”, 10);
p2.Print(); // Person Name: Park Age: 10
Person.PrintCount(); // calls Person.PrintCount() 3
Student.PrintCount(); // calls Student.PrintCount() 2

Person p3 = new Person();
p3.Print(); // Person Name: Age: 0
Person.PrintCount(); // calls Person.PrintCount() 4
Student.PrintCount(); // calls Student.PrintCount() 2

Console.WriteLine(“Number of Person: {0}”, Person.GetCount());
Console.WriteLine(“Number of Student: {0}”, Student.GetCount());
}
}
}

 

 

Lab4

Lab4 프로젝트 디렉토리 안에 모든 파일과 보고서 (2~3장)를 넣고 Lab4_학번_이름.zip  압축한 후 e-learning (http://lms.dankook.ac.kr/index.jsp)으로 제출 (10/24)

Lab4 – Interface

수업블로그에 클래스 OOP 참고하여, 본인이 작성한 Lab3를 인터페이스를 상속받아 구현한 객체지향적인 프로그램으로 바꾼다. 적어도 5개 이상의 Converter 클래스를 작성한다 (예시: degree <-> radian 변환, kilometer <-> mile 변환, kilogram <-> pound 변환, 등등). ConverterType 를 사용해줄 것!

http://www.unitconverters.net/
보고서는 출력해서 수업시작 전에 제출한다.

보고서의 내용은 기존 코드 분석과 이해한 내용 그리고 본인이 추가한 코드내용을 적는다..

Lab3

Lab3 프로젝트 디렉토리 안에 모든 파일과 보고서 (2~3장)를 넣고 Lab3_학번_이름.zip 압축한 후 e-learning

(http://lms.dankook.ac.kr/index.jsp)으로 제출 ()

Lab3 – Class/OOP

수업블로그에 클래스 OOP 참고하여, 본인이 작성한 Lab2를 객체지향적인 프로그램으로 바꾼다. 그리고 본인이 원하는 Converter 클래스를 하나더 추가 작성한다 (예시: degree <-> radian 변환, kilometer <-> mile 변환, kilogram <-> pound 변환, 등등). ConverterMode 를 사용해줄 것!

http://www.unitconverters.net/
보고서는 출력해서 수업시작 전에 제출한다.

보고서의 내용은 기존 코드 분석과 이해한 내용 그리고 본인이 추가한 코드내용을 적는다..

Person Array

Person[] pArray = new Person[3];

// 만약 Person 객체를 하나만 생성한 후 for문에서 공유해 사용할 경우
// 마지막으로 입력된 데이터로 모든 데이터값이 치환됨
Person p = new Person();
for (int i = 0; i < 3; i++) {
p.Name = Console.ReadLine();           // 입력정보
p.age = int.Parse(Console.ReadLine()); // 입력정보
pArray[i] = p;  // 리스트에 들어간 모든 원소는 동일한 p
}

 

Person[] pArray2 = new Person[3];
// 아래와 같이 for문 안에 Person p = new Person()와같이
// 새로운 객체를 생성해야 각자 다르게 입력된 정보가 들어가게 됨
for (int i = 0; i < 3; i++) {

Person p2 = new Person();
p2.Name = Console.ReadLine();           // 입력정보
p2.age = int.Parse(Console.ReadLine()); // 입력정보
pArray2[i] = p2; // 이때 p는 새로운 Person객체

}

 

Person2[] pArray3 = new Person2[3];
// 만약 Person2 객체의 name과 age는 static으로 사용할 경우
// static은 공유하는 것이므로, 마지막으로 입력된 데이터로 모든 데이터값이 치환됨
for (int i = 0; i < 3; i++) {

Person2 p3 = new Person2();

Person2.Name = Console.ReadLine(); 
Person2.Age = int.Parse(Console.ReadLine())
pArray3[i] = p3; // // p3 객체의 name과 age는 static이므로 모두 공유하기때문에, 배열의 모든 원소는 마지막에 들어간 정보로 셋팅

}

Parameter Passing: pass by value vs pass by reference vs pass by output

http://dis.dankook.ac.kr/lectures/hci10/entry/pass-by-value와-pass-by-reference와-pass-by-output-비교

 

pass value type by value (값형식을 값에 의한 전달)

static void Square1(int x)
{
x *= x;
Console.WriteLine(“The value inside the method: {0}”, x);
}
static void Main()
{
int i = 5;
Console.WriteLine(“i={0}”, i);
Square1(i);
Console.WriteLine(“i={0}”, i);
}
//i=5
//The value inside the method: 25
//i=5

 

pass reference type by value (참조형식을 값에 의한 전달)
-copy of reference가 전달

static void ChangeArray1(int[] arr)
{
arr[0]=888; // arr -> myArray이므로 원본 배열의 첫번째 값은 888로 변경
Console.WriteLine(“arr=” + string.Join(“,”, arr)); // .NET4만 동작
//Console.WriteLine(“arr=” + string.Join(“,”, Array.ConvertAll(arr, x => x.ToString()))); // .NET4  Earlier
arr = new int[5] {-3, -1, -2, -3, -4}; // local 변수로 새롭게 할당하여 지정
Console.WriteLine(“arr=” + string.Join(“,”, arr)); // .NET4
}
static void Main()
{
int[] myArray = {1, 4, 5};
Console.WriteLine(“myArray=” + string.Join(“,”, myArray)); // .NET4
ChangeArray1(myArray);
Console.WriteLine(“myArray=” + string.Join(“,”, myArray)); // .NET4
}
//myArray=1, 4, 5
//arr=888, 4, 5
//arr=-3, -1, -2, -3, -4
//myArray=888, 4, 5

 

 

pass value type by reference (값형식을 참조에 의한 전달)
ref 키워드 사용

static void Square2(ref int x)
{
x *= x;
Console.WriteLine(“The value inside the method: {0}”, x);
}
static void Main()
{
int i = 5;
Console.WriteLine(“i={0}”, i);
Square2(ref i);
Console.WriteLine(“i={0}”, i);
}
//i=5
//The value inside the method: 25
//i=25

 

pass reference type by reference (참조형식을 참조에 의한 전달)
ref 키워드 사용

static void ChangeArray2(ref int[] arr)
{
arr[0]=888; // 원본 배열의 첫번째 값은 888로 변경
Console.WriteLine(“arr=” + string.Join(“,”, arr)); // .NET4만 동작
arr = new int[5] {-3, -1, -2, -3, -4}; // 원본 배열이 다시 변경
Console.WriteLine(“arr=” + string.Join(“,”, arr)); // .NET4만 동작
}
static void Main()
{
int[] myArray = {1, 4, 5};
Console.WriteLine(“myArray=” + string.Join(“,”, myArray)); // .NET4
ChangeArray2(ref myArray);
Console.WriteLine(“myArray=” + string.Join(“,”, myArray)); // .NET4
}
// myArray=1, 4, 5
// arr=888, 4, 5
// arr=-3, -1, -2, -3, -4
// myArray=-3, -1, -2, -3, -4

 

pass value type by output (값형식을 output에 의한 전달)
out 키워드 사용

static void Square3(int x, out int result)
{
result = x*x;
Console.WriteLine(“The value inside the method: {0}”, result);
}
static void Main()
{
int i = 5;
Console.WriteLine(“i={0}”, i);
int result;
Square3(i, out result);
Console.WriteLine(“result={0}”, result);
}
//i=5
//The value inside the method: 25
//result=25

 

pass reference type by output (참조형식을 output에 의한 전달)
out 키워드 사용

static void ChangeArray3(out int[] arr)
{
//arr[0]=888; // use of unassigned out parameter ‘arr’ ERROR
arr = new int[5] {-3, -1, -2, -3, -4}; // 원본 배열이 변경
Console.WriteLine(“arr=” + string.Join(“,”, arr)); // .NET4
}
static void Main()
{
int[] myArray = {1, 4, 5};
Console.WriteLine(“myArray=” + string.Join(“,”, myArray)); // .NET4
ChangeArray3(out myArray);
Console.WriteLine(“myArray=” + string.Join(“,”, myArray)); // .NET4
}
//myArray=1, 4, 5
//arr=-3, -1, -2, -3, -4
//myArray=-3, -1, -2, -3, -4

 

static class vs singleton design pattern

공용 데이터를 저장하여 사용하고자 할 때, singleton 패턴이나 static 클래스를 사용한다.

싱글톤 패턴 (Singleton design pattern) -싱글톤 패턴이란 single instance object(해당 클래스의 인스턴스 하나)가 만들어지고, 어디서든지 그 싱글톤에 접근할 수 있도록 하기 위한 패턴

https://msdn.microsoft.com/en-us/library/ee817670.aspx

싱글톤 패턴 in C# https://msdn.microsoft.com/en-us/library/ff650316.aspx

/// Sample singleton object.
public sealed class SiteStructure
{

/// This is an expensive resource we need to only store in one place.
object[] _data = new object[10];

/// private constructor를 사용해서 static readonly로 객체 하나를 생성.
static readonly SiteStructure _instance = new SiteStructure();

/// 그 싱글톤에 접근하기 위한 property를 제공.
public static SiteStructure Instance
{

get { return _instance; }

}

/// private constructor, 즉 외부에서는 이 생성자를 부를 수 없음.
private SiteStructure()
{
// Initialize members, etc. here.
}

}// 싱글톤 객체를 인자로 전달 가능

SiteStructure site = SiteStructure.Instance;
OtherFunction(site); // Use singleton as parameter.

정적 클래스 (Static class)
-static 키워드를 사용한 정적 클래스는 정적 멤버만 포함 가능
-정적 클래스는 new 키워드를 사용하여 정적 클래스의 인스턴스를 생성할 수 없음
-정적 클래스는 봉인 클래스 (sealed class) 임
-static 클래스는 single-instance, global 데이터를 저장하여 사용하는 용도로 적당
-그러나, 싱글톤은 인자(parameter)나 객체(object)로 사용가능하나 정적클래스는 불가능

/// Static class example.
static public class SiteStatic
{

/// The data must be a static member in this example.
static object[] _data = new object[10];
/// C# doesn’t define when this constructor is run, but it will likely be run right before it is used.
static SiteStatic()
{
// Initialize all of our static members.
}

}

http://dis.dankook.ac.kr/lectures/hci10/entry/singleton-pattern과-static-class-비교