HW1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AreaCalculator
{
enum Figure { Triangle, Square, Rectangle, Parallelogram, Rhombus, Trapezoid, Circle }

class AreaCalculator
{
Figure? inputFigure = null;
double b = 1.0; // base/width
double h = 1.0; // height
double t = 1.0; // top
double r = 1.0; // radius/side
ConsoleColor[] colors = (ConsoleColor[])ConsoleColor.GetValues(typeof(ConsoleColor)); // ConsoleColor 배열

// CalculateArea 메소드는 실제 도형의 넓이 계산
double CalculateArea(Figure type) // if/elseif 또는 switch 구문
{
switch (type)
{
case Figure.Triangle:
return b * h * 0.5; // base * height * 0.5
case Figure.Square:
return r * r; // side * side
case Figure.Rectangle:
return b * h; // width * height
case Figure.Parallelogram:
return b * h; // base * height
case Figure.Rhombus:
return b * h * 0.5; // diagonal1 * diagonal2 * 0.5
case Figure.Trapezoid:
return (b + t ) * h * 0.5; // (base + top) * height * 0.5
case Figure.Circle:
return r * r * Math.PI; // PI * radius * radius
default:
return 0.0;
}
}

// GetAreaFormula 메소드는 출력시 사용
string GetAreaFormula(Figure type) // if/elseif 또는 switch 구문
{
switch (type)
{
case Figure.Triangle:
return b + ” x ” + h + ” x 0.5″;
case Figure.Square:
return r + ” x ” + r;
case Figure.Rectangle:
return b + ” x ” + h;
case Figure.Parallelogram:
return b + ” x ” + h ;
case Figure.Rhombus:
return b + ” x ” + h + ” x 0.5″;
case Figure.Trapezoid:
return “(” + b + ” + ” + t + “) x ” + h + ” x 0.5″;
case Figure.Circle:
return “3.14 x ” + r + ” ^2″;
default:
return “”;
}
}

// GetFigureFromName 메소드는 사용자 입력으로부터 Figure 반환
Figure? GetFigureFromName(string name) // if/elseif 또는 switch 구문
{
switch (name)
{
case “삼각형”:
case “Triangle”:
case “TRIANGLE”:
return Figure.Triangle;
case “정사각형”:
case “Square”:
case “SQUARE”:
return Figure.Square;
case “직사각형”:
case “Rectangle”:
case “RECTANGLE”:
return Figure.Rectangle;
case “평행사변형”:
case “Parallelogram”:
case “PARALLELOGRAM”:
return Figure.Parallelogram;
case “마름모꼴”:
case “Rhombus”:
case “RHOMBUS”:
return Figure.Rhombus;
case “사다리꼴”:
case “Trapezoid”:
case “TRAPEZOID”:
return Figure.Trapezoid;
case “원”:
case “Circle”:
case “CIRCLE”:
return Figure.Circle;
default:
return null;
}
}

// GetFigureColor 메소드는 각도형별 ConsoleColor 값
ConsoleColor GetFigureColor(Figure poly)
{
return colors[(int)poly+1]; // colors[0]은 검정색 바탕에서는 안보임
}

// GetValueFromInput 메소드는 각도형별 추가적인 입력 값
double GetValueFromInput(string input)
{
double value = 0.0;
Console.Write(“{0} 길이: “, input);  // input 인자 출력
while (!double.TryParse(Console.ReadLine(), out value))
{
Console.WriteLine(“잘못된 입력입니다. 다시 입력해주세요.”);
Console.Write(“{0} 길이: “, input);  // input 인자 출력
}
return value;
}

// 도형(Figure) 입력
Figure? GetInputFigure()
{
Figure? input = null;
do
{
Console.Write(“도형의 종류를 입력해주세요(삼각형/정사각형/직사각형 등등 또는 Triangle/Square/Rectangle): “);
input = GetFigureFromName(Console.ReadLine());
if (input == null)  Console.WriteLine(“잘못된 입력입니다.”);
} while (input == null);
return input;
}

// GetKeyboardInput 메소드는 사용자 입력
public void GetKeyboardInput()
{
// 도형 입력
inputFigure = GetInputFigure();

// 도형에 따른 추가입력
if (inputFigure == Figure.Triangle)
{
this.b = GetValueFromInput(“삼각형 밑변(Base)”);
this.h = GetValueFromInput(“삼각형 높이(Height)”);
}
else if (inputFigure == Figure.Square)
{
this.r = GetValueFromInput(“정사각형 한변(Side)”); // use r (side)
}
else if (inputFigure == Figure.Rectangle)
{
this.b = GetValueFromInput(“직사각형 가로(Width)”);
this.h = GetValueFromInput(“직사각형 세로(Height)”);
}
else if (inputFigure == Figure.Parallelogram)
{
this.b = GetValueFromInput(“평행사변형 밑변(Base)”);
this.h = GetValueFromInput(“평행사변형 높이(Height)”);
}
else if (inputFigure == Figure.Rhombus)
{
this.b = GetValueFromInput(“마름모꼴 대각선길이(Width)”);
this.h = GetValueFromInput(“마름모꼴 대각선높이(Height)”);
}
else if (inputFigure == Figure.Trapezoid)
{
this.t = GetValueFromInput(“사다리꼴 윗변(Top)”);
this.b = GetValueFromInput(“사다리꼴 아래변(Base)”);
this.h = GetValueFromInput(“사다리꼴 높이(Height)”);
}
else if (inputFigure == Figure.Circle)
{
this.r = GetValueFromInput(“원 반지름(Radius)”);
}
}

public void Print()
{
Figure poly = inputFigure ?? default(Figure);
string formula = GetAreaFormula(poly);
double area = CalculateArea(poly);
Console.ForegroundColor = GetFigureColor(poly);
Console.WriteLine(“{0} 도형의 넓이는 {1} = {2:F1} 입니다.”, poly, formula, area);
Console.ForegroundColor = ConsoleColor.White;
}

public void PrintAllFigureArea()
{
foreach (Figure poly in Figure.GetValues(typeof(Figure))) // 각 도형마다
{
Console.WriteLine();
Console.ForegroundColor = GetFigureColor(poly); // 각 도형의 색깔
Console.WriteLine(“\t {0}”, poly); // 각 도형의 이름 출력

// 표 가로 상단
Console.Write(“{0,6}”, ” “);
for (int k = 1; k <= 10; k++)
{
Console.Write(“{0,6}”, k);
}
Console.WriteLine();
// 표 본문
for (int i = 1; i <= 10; i++)
{
Console.Write(“{0,6}”, i); // 표 세로
this.b = this.r = i;
for (int j = 1; j <= 10; j++)  // 각 도형 별 Area 값
{
this.h = j;
if (poly == Figure.Triangle || poly == Figure.Rectangle || poly == Figure.Parallelogram || poly == Figure.Rhombus)
{
Console.Write(“{0,6:F1}”, CalculateArea(poly));
}
else if (poly == Figure.Square || poly == Figure.Circle)
{
if (i == j) Console.Write(“{0,6:F1}”, CalculateArea(poly));
else Console.Write(“{0,6}”, ” “);
}
else if (poly == Figure.Trapezoid)
{
this.t = j; // 사다리꼴의 경우에만 값을 하나 더 추가
Console.Write(“{0,6:F1}”, CalculateArea(poly));
}
}
Console.WriteLine();
}
Console.WriteLine();
}
}
}

class Program
{
static void Main(string[] args)
{
AreaCalculator a = new AreaCalculator();
a.PrintAllFigureArea();
do
{
a.GetKeyboardInput();
a.Print();
Console.WriteLine(“다시 하려면 ENTER 키를 누르시고 종료하려면 ESC 키를 누르세요”);
} while (Console.ReadKey().Key != ConsoleKey.Escape);

}
}
}

class indexer, property, abstract, sealed

Indexer (인덱서)
http://dis.dankook.ac.kr/lectures/hci09/entry/Indexer

Property (속성)
http://dis.dankook.ac.kr/lectures/hci09/entry/Property

Abstract Class (추상 클래스)
http://dis.dankook.ac.kr/lectures/hci09/entry/Abstract-class

Sealed Class (봉인 클래스)
http://dis.dankook.ac.kr/lectures/hci09/entry/Sealed-Class

polymorphism (다형성)
– Shape/Circle/Rectangle/Triangle/Square 클래스
– class 및 inheritance
– abstract class 및 polymorphism

 

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

 

HW2

단국대학교 멀티미디어공학전공 HCI프로그래밍2 (2015년 가을학기) 실습

날짜: 2015년 10월 2일

 

– 실습번호 : lab-02 (Due by 10/16)

– 실습제목 : class, abstract class, inheritance, property, list, array, dictionary

– 실습요약 : 평면 도형의 넓이(area)와 둘레(perimeter) 구하기

– 준비자료 : http://www.allsubjects4you.com/Area-and-perimeter-of-plane-figures.htm

http://www.science.co.il/Formula.asp

http://www.mathsisfun.com/area-calculation-tool.html

http://www.calculatoredge.com/enggcalc/perimeter.htm

 

10/16까지 online.dankook.ac.kr 이러닝으로 source code, executable file, solution/project VC# file, 보고서(12-font 2~3 page)를 학번_이름_Ex2.zip으로 묶어서 이러닝에 제출한다.

보고서 (30%)  프린트는 10/16 수업 시간에 제출한다. 그리고 보고서와 함께 ‘직접 손으로 쓴 본인 프로그램 소스코드’를 제출한다.

 

 

– 실습문제

  1. public enum FigureType { Triangle, Square, Rectangle, Parallelogram, Rhombus, Trapezoid };

 

  1. Figure 추상클래스를 상속받은 Triangle, Square, Rectangle, Parallelogram, Rhombus, Trapezoid 클래스는 각 도형의 넓이(Area) 및 둘레(Perimeter)를 계산한다. Figure 추상클래스는 다음을 포함한다.

+ public abstract ConsoleColor Color { get; }

+ public abstract double Area { get; }

+ public abstract string AreaFormula { get; }

+ public abstract double Perimeter { get; }

+ public abstract string PerimeterFormula { get; }

 

  1. FigureCalculator 추상클래스를 상속받은 TriangleCalculator, SquareCalculator, RectangleCalculator, .. 등 클래스는 실제 Triangle, Square, 등을 이용하여 넓이 및 둘레를 출력한다. FigureCalculator 추상클래스는 다음을 포함한다.

+ public Figure GeometryFigure = null;

+ public string Title {

get { return GeometryFigure.GetType().ToString() + “ 넓이/둘레 구하기”; }

}

+ public abstract void PrintTable()는 해당 도형의 넓이/둘레 표를 출력

+ public abstract void GetUserInputAndCalculateArea()와 GetUserInputAndCalculatePerimeter()는 사용자 입력에 따른 도형의 넓이/둘레 출력

 

  1. FigureCalculatorFactory 클래스는 사용자가 입력한 도형에 따라 원하는 실제 FigureCalculator (즉, TriangleCalculator, SquareCalculator, 등등) 객체를 생성하여 계산한다. 이 클래스는 다음의 메소드 (Method)만을 갖는다.

+ public FigureCalculator GetInstance(FigureType inputFigure)

 

  1. Program 클래스에서는 사용자의 입력에 따라 FigureCalculatorFactory를 이용하여 도형의 넓이 및 둘레를 계산하고, 테스트한 모든 결과를 다시 출력한다.

+ FigureType? GetFigureTypeFromName(string name)은 Dictionary를 이용하여 사용자가 입력한 도형 이름으로부터 FigureType을 반환

+ 사용자가 테스트한 도형의 넓이 및 둘레 계산을 Array나 ArrayList에 저장해 두었다가 do-while를 벗어나서 프로그램을 종료할 시 전체 리스트를 출력

 

  1. 사용자의 잘못된 입력에 따른 처리를 반드시 포함해야 하며, 그 외에 본인이 더 테스트해보고 싶은 method나 routine을 추가하라. 실행 화면과 코드를 첨부하시오.

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-비교

Protected

public class Car
{

// member field
private bool disel;     // disel은 파생 클래스에서 사용하지 못함
protected bool gasoline;// gasoline은 파생 클래스에서 사용가능하나 클래스 외부에서는 호출하지 못함
protected int wheel = 4;// wheel은 파생 클래스에서 사용가능하나 클래스 외부에서는 호출하지 못함

// constructor
protected Car() { disel = true; gasoline = true;  }
protected Car(int wheel) { this.wheel = wheel; disel = false; gasoline = false; }

// method
public void Move()
{
if (disel)
Console.Write(“Car 디젤”);
else
Console.Write(“바퀴 {0} 자동차가 굴러간다.”, wheel);
}

}

public class Sedan : Car
{

// member field
private bool gasoline;  // 파생 클래스에서 기반클래스에 멤버필드명이 같다면 default는 자신의 멤버부터 호출 &
Sedan.gasoline은 Car.gasoline을 숨김 => private new bool gasoline와 같은 의미

// constructor
public Sedan() { gasoline = false;  }  // Sedan() : base() 호출
public Sedan(int wheel) : base(wheel) { gasoline = true; } // Sedan(int wheel) :
base(int wheel)를 호출 – protected 생성자는 기반 클래스의 생성자 호출 base에서 사용됨

// method
public void SedanMove()
{

// base의 gasoline과 this의 gasoline을 구분해야하는 경우
if (base.gasoline)
Console.Write(“Car가솔린”);
if (this.gasoline)
Console.Write(“Sedan 가솔린”);

Console.WriteLine(“바퀴 {0} 세단자동차가 굴러간다.”, wheel);

}

static void Main(string[] args)
{

// error CS1540: ‘Car’형식의 한정자를 통해 보호된 ‘Car.Car()’ 멤버에 액세스할 수 없습니다. 한정자는 ‘Sedan’ 형식이거나 여기에서 파생된 형식이어야 합니다.
//Car myCar = new Car();    // 기반 클래스 생성자 Car()는 상속되지 않음. 따라서 new를 이용하여 객체를 생성할 수 없음.
//myCar.Move();             //  myCar 객체없이 myCar.Move() 호출할 수 없음
//Console.WriteLine(“마이카의 바퀴는 {0}개 이다.”, myCar.wheel); // myCar 객체없이 myCar.wheel 호출할 수 없음

// 바퀴 4개 디젤 자동차
Sedan myCar1 = new Sedan();
myCar1.Move();       // Car를 상속받았기 때문에 Move() 메소드를 사용할 수 있음
myCar1.SedanMove();  // Sedan 자신의 메소드 사용가능
Console.WriteLine(“마이카의 바퀴는 {0}개 이다.”, myCar1.wheel); // 상속된 객체에서 기반 객체의 protected 멤버 필드 호출가능

Console.WriteLine();

// 바퀴 6개 가솔린 자동차
Sedan myCar2 = new Sedan(6);
myCar2.Move();       // Car를 상속받았기 때문에 Move() 메소드를 사용할 수 있음
myCar2.SedanMove();  // Sedan 자신의 메소드 사용가능
Console.WriteLine(“마이카의 바퀴는 {0}개 이다.”, myCar2.wheel); // 상속된 객체에서 기반 객체의 protected 멤버 필드 호출가능

}

}

new vs virtual vs override Method

class Base
{

public void Print() { Console.WriteLine(“Base Print”); }

}

class Derived : Base
{

public void Print() { Console.WriteLine(“Derived Print”); }

}

class Program
{

static void Main(string[] args)
{

Base b = new Base();
Derived d = new Derived();
Base e = d;
b.Print(); // Base Print
d.Print(); // Derived Print (부모클래스의 메소드와 같은 이름으로 메소드를 정의하면 부모의 메소드는 숨겨짐)
e.Print(); // Base Print (원래 e는 Derived 객체이나 Base 데이타형이므로 Base의 Print 메소드 호출)

}

}

 

new 메소드 새정의 (위의 코드는 아래와 똑같음. new 키워드를 사용하여 명시적으로 명확하게 적어주도록 함)

 

class Base
{
public void Print() { Console.WriteLine(“Base Print”); }
}
class Derived : Base
{
public new void Print() { Console.WriteLine(“Derived Print”); } // 부모클래스의 Print 메소드는 새로 정의
public void BasePrint() { base.Print(); } // 부모클래스의Print는 여전히 사용 가능
}
class Program
{
static void Main(string[] args)
{
Base b = new Base();
Derived d = new Derived();
Base e = d;
b.Print(); // Base Print
d.Print(); // Derived Print (부모클래스의 메소드와 같은 이름으로 메소드를 새로 정의)
d.BasePrint();
e.Print(); // Base Print (원래 e는 Derived 객체이나 Base 데이타형이므로 Base의 Print 메소드 호출)
}
}

 

virtual – override 메소드 재정의 (Method Overriding) run-time에서 객체의 DataType에 따른 late-binding이 일어남

 

class Base
{
public virtual void Print() { Console.WriteLine(“Base Print”); }
}
class Derived : Base
{
public override void Print() { Console.WriteLine(“Derived Print”); } // 부모클래스의 Print 메소드는 재정의
public void BasePrint() { base.Print(); } // 부모클래스의Print는 여전히 사용 가능
}
class Program
{
static void Main(string[] args)
{
Base b = new Base();
Derived d = new Derived();
Base e = d;
b.Print(); // Base Print
d.Print(); // Derived Print (부모클래스의 메소드와 같은 이름으로 메소드를 재정의)
d.BasePrint();
e.Print(); // Derived Print (원래 e는 Derived 객체이므로 late-binding에 의해서 Derived 의 Print 메소드 호출)
}
}

C# constructor usage guideline

private constructor는 정적 메소드와 속성 (static method & property)만 있는 경우 사용함.
http://msdn.microsoft.com/en-us/library/vstudio/kcfb85a6.aspx

public class Counter
{
private Counter() { }
public static int currentCount;
public static int IncrementCount() {  return ++currentCount; }
}
class TestCounter
{
static void Main()
{
// If you uncomment the following statement, it will generate
// an error because the constructor is inaccessible:
// Counter aCounter = new Counter();   // Error
Counter.currentCount = 100;
Counter.IncrementCount();
Console.WriteLine(“New count: {0}”, Counter.currentCount);
// Keep the console window open in debug mode.
Console.WriteLine(“Press any key to exit.”);
Console.ReadKey();
}

} // Output: New count: 101

protected constructor는 추상클래스 (abstract class)에서 사용을 권고함. 추상 클래스를 상속받는 파생클래스에서 파생 클래스 생성자가 부모 클래스 즉, 추상 클래스를 초기화 하기 위해 추상 클래스 생성자를 호출 할 수 있도록 지원함.
http://msdn.microsoft.com/en-us/library/bcd5672a%28v=vs.80%29.aspx
http://msdn.microsoft.com/ko-kr/library/ms229047(v=vs.100).aspx

public abstract class Shape
{
protected Shape(string name) { this.name = name; }
private string name;
public virtual void Print() { Console.Write(this.name); }
}
public class Triangle: Shape
{
public Triangle(string name): base(name) { this.bottom = 1; this.height = 1 }
private double bottom, height;
public override void Print()
{
base.Print();
Console.WriteLine(” 밑변: {0} 높이: {1}”, this.bottom, this.height);
}
}
public class Rectangle: Shape
{
public Rectangle(string name): base(name) { this.width = 2; this.height = 3 }
private double width, height;
public override void Print()
{
base.Print();
Console.WriteLine(” 가로: {0} 세로: {1}”, this.width, this.height);
}
}
class ShapeTest
{
static void Main()
{
// Shape s = new Shape(“도형”);   // Error CS0144, Cannot create an instance of the abstract class
Shape s = new Triangle(“삼각형”);
s.Print(); // 삼각형 밑변: 1 높이: 1
s = new Rectangle(“직사각형”);
s.Print(); // 직사각형 가로: 2 세로: 3
}
}