
노는게 공부하는거고
공부하는게 노는것처럼
by 초피쌀
 skin by 토리
|
{ private Car[] carArray;
public Cars() { carArray = new Car[4]; carArray[0] = new Car("FeeFee", 200, 0); carArray[1] = new Car("Fee", 200, 0); carArray[2] = new Car("Zippy", 200, 0); carArray[3] = new Car("Fred", 200, 0);
} }
main() { foreach (Car c in carLot) { Console.WriteLine("Name : {0} ", c.PetName); Console.WriteLine("Max Speed : {0}", c.MaxSpeed); } }
그러나 이 코드를 실행하려고 하면 , Cars 클래스에 GetEnumerator() 메소드가 구현되지 않았다는 컴파일 에러가 발생할 것이다. 이 메소드는 System.Collections 네임스페이스에 숨어 있는 IEnumerable 인터페이스에 정의되어 있다.
// foreach 구문을 이용해서 하위 형식을 얻으려면, 컨테이너가 반드시 IEnumerable 을 구현해야 한다.
public class Cars : IEnumerable // IEnumerator 는 필요하지 않다! { // 이 클래스에는 자동차의 배열이 들어 있다.
public IEnumerator GetEnumerator() { // 이제는 내부 배열로부터 IEnumerator 를 반환한다! return carArray.GetEnumerator(); } }
인터페이스의 멤버는 접근 한정자를 취하지 않는다. (인터페이스의 메소드는, 지원하는 형식에서 이 멤버들을 구현할 수 있어야 하므로, 암시적으로 public 이다.).
// 인터페이스는 기본 클래스를 갖지 않는다! public interface IPointy { byte GetNumberOfPoints(); // 암시적으로 public이고 abstract 이다. }
인터페이스를 지원해서 C#클래스의 기능을 확장하려면, 형식 정의 부분에 쉼표로 구분해서 해당 인터페이스의 목록을 적으면 된다. 주의할 점은, 기본 클래스가 있는 경우 기본 클래스 이름 먼저 와야 한다는 것이다.
인터페이스 구현은 '전부 또는 무 ' 명제를 따른다. 만약 10개의 멤버가 정의된 인터페이스를 구현하는 클래스가 있다면 이 클래스에서 10 개의 추상 항목을 모두 채워야 한다.
NOTE 추상 클래스가 다른 인터페이스를 지원하는 경우 해당 인터페이스의 멤버를 명시적으로 abstract로 정의하기만 하면 이 인터페이스의 멤버를 구현하지 않은 채로 두어도 무방하다.
값 형식과 참조 형식 이해하기
// 구조체는 값 형식이다. struct FOO { public int x,y; }
// 기본 생성자를 이용해서 생성할 때는 'new'키워드가 생략 될수 있지만, 필드들은 모두 사용되기 전에 할당되어야 한다. FOO f1 = new FOO(); f1.x = 100; f1.y = 100;
FOO f2 = f1; // f2.x 를 변경해도 f1.x는 변경되지 않는다. f2.x = 900;
이와 반대로, 참조 형식(클래스)은 가비지 컬렉션의 대상인 힙에 할당된다. 힙에 할당된 참조 형식은 가비지 컬렉터에 의해 제거되기 전까지는 계속 메모리에 남아 있게 된다. 기본적으로, 참조 형식을 할당하면 메모리에 있는 동일한 객체에 대한 새로운 참조자가 만들어 진다.
class FOO { public int x, y; } 이렇게 바꾸어서 테스트해보면 이제 관리 힙에 있는 동일한 객체를 지시하는 두 개의 참조자가 생겨났기 때문이다. 그래서 f2 참조자의 x값을 변경하면 f1.x도 같은 값을 나타내게 된다.
참조 형식을 포함하는 값 형식
InnerRef (내부에 참조 형식을 포함하는 값 형식) InnerRef 변수 하나를 다른 InnerRef 변수에 할당하면 어떤 일이 벌어 질까? 내부 참조 형식은 새로운 InnerRef 변수로 완전히 복사되지 않는다. 구조체는 서로 다른 두개가 되지만, 참조자들은 메모리에 있는 동일한 객체를 지시하게 된다.
마스터 노드 : System.Object
C#에서는 모든 데이터 형식(값 기반이든 참조 기반이든)은 결국 공용 기본 클래스인 System.Object로 부터 파생한다. Object가 기본 클래스로 명시되어 있지 않은 것을 볼 수 있는데, 다른 기본 클래스를 명시하지 않으면 기본 클래스가 Object 인 것으로 간주된다.
// 객체 참조자 비교... ObjTest c1 = new ObjTest();
// c1 에 대한 참조자들을 만든다. ObjTest c2 = c1; object o = c2;
//세 인스턴스가 모두 메모리상의 동일한 객체를 가리키고 있나? if(o.Equals(c1) && c2.Equals(o)) Console.WriteLine("Same instance");
Equals()는 기본적으로 값 의미구조가 아닌 참조 의미구조로 두 객체의 변수를 비교하게 되어 있다. c1, c2 그리고 o 가 모두 메모리상의 동일한 객체를 가리키기 때문에, 같은 비교 결과는 참이다.
System.Object 의 기본 기능 재정의 하기
System.Object에 미리 준비된 기능으로 충분하긴 하지만, 이 동작들을 상속한 메소드를 재정의하는 것이 일반적이다. 파생 클래스에서 이 가상 멤버들을 임의대로 구현하고 싶으면 C#의 'override' 키워드를 사용하면 된다.
System.Object의 정적 멤버들
값 기반 또는 참조 기반으로 동등 비교를 할 수 있는 두 개의 정적 멤버가 정의되어 있다.
//System.Object의 정적 멤버. Person p3 = new Person("Sally", "Jones", "333", 4); Person p4 = new Person("Sally", "Jones", "333", 4); // p3와 p4의 상태가 동일한가? 그러타! Console.WriteLine("P3 and P4 have same state : {0}", object.Equals(p3, p4));
// 이 둘은 메모리상의 동일한 객체인가 ? 아니다! Console.WriteLine("P3 and P4 are pointing to same object : {0} ", object.ReferenceEquals(p3, p4));
.NET 기본 클래스 라이브러리에 정의되어 있는 모든 클래스, 구조체, 열거형 그리고 델리게이트는 항상 System.Object의 public 멤버를 지원한다. 그러나 인터페이스는 System.Object 또는 다른 어떤 기본 클래스로부터 파생되지 않는다!!!
문자열 데이터로부터 값 구문분석하기
.NET 데이터 형식은 이 형식을 표현하는 문자열로부터 본래 형식의 변수를 생성(즉, 구문분석 parsing)할 수 있다. 입력한 데이터를 숫자 값으로 변환하고 싶을 때 특히 유용하게 사용될 수 있다.
double MyDbl = double.Parse("99.884"); int myInt = int.Parse("8"); char myChar = char.Parse("w");
값 형식과 참조 형식 간의 변환 : 박싱(boxing)과 언박싱(unboxing)
.NET 에서는 형식을 크게 두 가지 범주(값 기반과 참조 기반)로 나뉘는데, 경우에 따라 한 범주에 속하는 변수를 다른 범주의 변수로 나타낼 필요가 있ㅇ르 수 있다. C#에는 값 형식과 참조 형식 간의 변환을 간단하게 할 수 있는 메커니즘이 있는데, 이를 박싱(boxing)이라고 부른다.
// 값 데이터 포인트를 만든다. short s = 25;
// 값을 객체 참조로 박스한다. object objShort = s;
박싱은 명시적으로 값 형식을 이에 상응하는 참조 형식으로 변환하는 과정이라고 정의할 수 있다. 언박싱은 객체 참조에 들어 있는 ㄱ밧을 이에 상응하는 값 형식으로 변환해 스택에 올려놓는 과정을 일컫는 용어이다.
// 참조를 이에 상응하는 short로 언박스한다. short anotherShort = (short)objShort;
알맞은 데이터 형식으로 언박스한느 것은 상당히 주의를 요하는 작업이다.
// foreach 를 사용하면 배열의 크기를 알아낼 필요가 없다.
public static void Main(string[] args) { foreach(string s in args) { Console.WriteLine("Arg : {0} ", s); } }
객체 생성하기 : 생성자 // 에러! 할당되지 않은 지역 변수 사용! 'new'를 사용
HelloClass c1; c1.SayHi();
// 한 줄의 코드에서 새로운 객체 선언하고 생성하거나.. HelloClass c1 = new HelloClass(); // 또는 두줄 HelloClass c2; c2 = new HelloClass();
'new'키워드는 지정된 객체에 필요한 정확한 바이트 수를 할당해서 관리 힙에 충분한 메모리를 확보하는 일을 담당한다. 앞의 코드 예에서 할당된 두 객체 (c1, c2)는 HelloClass 형식의 고유한 인스턴스를 가리킨다. c#의 객체 변수는 사실 객체가 아니고 메모리에 있는 객체에 대한 참조자이다.
c# 멤버 변수 초기화
c#에서는 멤버 변수를 선언하면서 동시에 초기 값을 할당할 수 있다.(c++과 같은 다른 언어에서는 이런방식의 멤버 초기화가 불가능하다)
// 이 방법은 기본 값이 아닌 다른 값을 할당 하고 // 각 생성자에 동일한 초기화 코드를 적기 싫은 경유에 유용하다. class Test { private int myInt = 9; private string myStr = "My initial value."; private HotRod viper = new HotRod(200, "Chuchy", Color.ReD); ... }
Console 클래스를 이용한 기본 입출력
Console은 System 네임스페이스에 정의 되어 있는 형식이다. System.Console의 주요 메소드는 Read(), ReadLine(), Write(), WriteLine() 등이 있는데, 이들은 모두 static 으로 정의되어 있다.
Write() 메소드는 텍스트를 캐리지 리턴 없이 출력 스트림으로 내보낸다. Read()를 이용하면 입력 스트림으로부터 하나의 문자를 받아 올 수 있다.
텍스트 출력 포맷 지정 {0}, {1}와 같은 토큰
//문자열 포맷하기... Console.WriteLine("Int is : {0} \ nFloat is : {1} \ nYou Are : {2} ", theInt, theFloat, myIO.ToString());
WriteLine()의 첫번째 매개변수는 {0}, {1},{2}와 같은 포맷 지정자가 포함된 포맷 문자열을 나타낸다. WriteLine()의 나머지 매개변수는 각각의 포맷 지정자에 들어갈 값들이다 또한 WriteLine()은 객체 배열을 포맷 지정자로 지정할 수 있도록 오버로드 되어 있다.
// 포맷 지정자를 객체 배열로 채운다. object[] stuff = {"Hello", 20.9, 1, "There", "83", 99.933} ; Console.WriteLine("The Stuff : {0}, {1}, {2}, {3}, {4}, {5} ", stuff);
하나의 포맷 지정자를 통해 해당 문자열 안에 반복해서 쓸 수 있다. 예를 들어 , "9Number9Number9"와 같은 문자열을 만들고 싶은 경우
Console.WriteLine("{0} Number{0}Number{0}", 9);
CREATE TABLE member ( mnum NUMBER(3) CONSTRAINT member_mnum_pk PRIMARY KEY, id VARCHAR2(25) CONSTRAINT member_id_uk UNIQUE, pw VARCHAR2(25) CONSTRAINT member_pw_nn NOT NULL, name VARCHAR2(25) CONSTRAINT member_name_nn NOT NULL, state NUMBER(1) CONSTRAINT member_state_ck CHECK(state in(0,1)) );
create sequence member_no start with 1 increment by 1;
create table reservation ( mnum NUMBER(3) CONSTRAINT reservation_mnum_fk REFERENCES member(mnum) ON DELETE CASCADE , start_date date , end_date date , tnum number(3) CONSTRAINT reservation_tnum_fk REFERENCES travel(tnum) ON DELETE CASCADE );
drop table reservation; create table member_grade ( mnum number(3) , mpoint number(10) , grade varchar2(25) );
alter table member_grade add constraint member_grade_fk foreign key(mnum) references member(mnum);
-- 여행 테이블 create table travel ( tnum number(3) constraint travel_tnum_pk primary key, t_name varchar(25) constraint travel_t_name_nn not null , t_location varchar(25) constraint travel_t_location_nn not null, t_price number(10) constraint travel_t_price_nn not null );
-- 여행 일정 테이블 create table travel_plan ( tnum number(3) constraint travel_plan_tnum_fk REFERENCES travel(tnum), tplan date );
-- 테마 테이블 create table theme ( thm_num number(3) constraint theme_thm_num_pk primary key, thm_name varchar(25) );
-- 테마의 여행지 테이블 create table theme_travel ( thm_num number(3) constraint theme_travel_thm_num_fk references theme(thm_num), tnum number(3) constraint theme_travel_tnum_fk references travel(tnum) );
|