'분류 전체보기'에 해당되는 글 317건

  1. 2009.09.30 인덱스가 있지만 인덱스를 안 타는 경우
  2. 2009.09.30 MS-SQL 실행 계획 확인
  3. 2009.09.30 Inline 쿼리 VS 저장 프로시저
  4. 2009.09.30 SUBQUERY와 INLINE-VIEW의 차이 1
  5. 2009.09.30 singleton pattern 싱글톤 패턴
  6. 2009.09.29 Hands-on Labs for EL 4.1 and Unity 1.2
  7. 2009.09.29 닷넷에서 native dll 사용하기
  8. 2009.09.28 [MS SQL] ldf 파일 사이즈 줄이기 또는 삭제하기
  9. 2009.09.24 간단 invoke, casting Sample -1 ... & 필드, 프로퍼티, 메소드
  10. 2009.09.24 string 으로 동적 참조 2 & System.Activator.CreateInstance
  11. 2009.09.24 참고 사이트.
  12. 2009.09.24 간단 예제.
  13. 2009.09.24 * Conditional 어트리뷰트 사용
  14. 2009.09.24 * DllImport 어트리뷰트
  15. 2009.09.24 Attrubute(어트리뷰트)
  16. 2009.09.24 Attribute Oriented Programming
  17. 2009.09.24 [LAST] Sample-3 xml->class & config 파일 연동
  18. 2009.09.24 AOP [Aspect Oriented Programming]
  19. 2009.09.24 [XSD.EXE] XML <->CLASS & Serialization
  20. 2009.09.23 XML 제어 - 읽기......
  21. 2009.09.23 CONFIG XML 의 Element 와 Attribute 를 XPATH 로 값 가져오는 방법
  22. 2009.09.23 Sample-2 .. 예제파일들과 호출..여러 가지것들
  23. 2009.09.23 사용자가 임의로 만든 any XML configuration file 제어 1
  24. 2009.09.23 Unity Application Block 에서의 Configuration 1
  25. 2009.09.23 Error 처리
  26. 2009.09.23 Config 의 type 과 DLL 과 연결 관련...
  27. 2009.09.23 Sample - 1
  28. 2009.09.23 XML Config 제어하기.
  29. 2009.09.15 C#2.0 , C# 3.0 New Features
  30. 2009.09.15 [KEY POINT] NUNIT ... . 핵심..
posted by 방랑군 2009. 9. 30. 14:01

참조 : http://elky.tistory.com/210

1. 인덱스  컬럼의 변형
select * from table  where LOWER(name)  ='word';
select * from table  where idx - 1 = 5;
이 처럼 인덱스에 변형을 가하게 되면, DBMS가 인덱스를 이용하지 않는다.

2. NOT 또는 IN 연산자 사용
NOT일 경우 무조건 인덱스를 안타는 것이 아니다.
NOT일 경우에도 인덱스를 타긴 타지만, 일반적으로, NOT에 사용된 값이 아닌 데이터의 비율이 높은 경우가 많기 때문에 인덱스를 타지 않는 경우가 많다.
마찬가지로 IN일 경우에도, IN에 포함된 데이터들의 비율이 매우 높다면 FULL SCAN을 하는 것이 낫다고 DBMS가 판단하면 인덱스를 타지 않는다.


3. 와일드 카드 LIKE문장에서 범위를 전체를 지정시
select * from table  where name like '%word'; 
문자열로 이루어진 값을 인덱스로 잡았을 때, %가 앞쪽에 사용되면 정렬 순서를 사용할 수 없으므로 테이블 FULL SCAN이 이루어진다.

select * from table  where name like 'word%'; 
당연한 얘기지만 쿼리가 이런 경우 인덱스를 탄다. 문자열 정렬 순서를 그대로 이용할 수 있기 때문이다.

4. 복합 컬럼 index에서 조건이 잘못되여 index 가 적용 되지 못하는경우
select * from table where name = 'word' or idx = 5

name과 idx가 둘다 인덱스가 걸려있는 경우라해도, DBMS가 최적의 OR 조건을 뽑기 힘들어, FULL SCAN 하는 경우가 많다.

5. Optimizer 의 선택
select * from table  where name ='word' and  id ='elky'; 

인덱스가 name 과   id로 2개가 있을 경우 id나 name 인덱스 중 하나가 선택될수도 있고, 둘다 선택 될 수도있다.
어떤 방식으로 선택하는냐가 속도에 중요할수도있다. 즉 실행 계획을 추적해서 원하는 결과가 나오도록 관리가 필요하다

'IT > DB' 카테고리의 다른 글

한 테이블에 존재하는 인덱스의 종류에 따른 차이  (0) 2009.09.30
인덱스 정리  (0) 2009.09.30
MS-SQL 실행 계획 확인  (0) 2009.09.30
Inline 쿼리 VS 저장 프로시저  (0) 2009.09.30
SUBQUERY와 INLINE-VIEW의 차이  (1) 2009.09.30
posted by 방랑군 2009. 9. 30. 14:00

참조 : http://elky.tistory.com/218


MSSQL에선 실행 계획을 통해 인덱스를 타는지, 어떠한 쿼리가 더 빠른지 측정할 수가 있습니다.

쿼리
Set Statistics Profile { ON | OFF } -- 쿼리 결과에 실행 계획을 포함
Set Statistics IO {ON | OFF}         -- 페이지의 입출력 수를 알 수 있다.
Set Showplan_All { ON | OFF }     -- 실행 계획만 보는 옵션

실행 계획은 SQL Server 쿼리 프로세서가 각 문을 실행할 때 취한 단계를 나타내는 계층적 트리를 이루는 행 집합으로 정보를 반환합니다. 출력에 반영된 문에는 문의 텍스트가 있는 단일 행이 포함되고, 이 단일 행 뒤에는 실행 단계에 대한 자세한 정보가 있는 몇 개의 행이 있습니다 아래 표에서는 출력에 포함된 열을 보여 줍니다.

열 이름

설명

Rows

실행된 행수

Executes

Loop 일 경우 Loop 실행 된 횟수

StmtText

PLAN_ROW 형식이 아닌 행에 대해 이 열에는 Transact-SQL 문의 텍스트가 포함됩니다. PLAN_ROW 유형의 행에 대해서는 이 열에 작업에 대한 설명이 포함됩니다. 이 열에는 물리적 연산자가 포함되며 논리 연산자가 포함될 경우도 있습니다. 이 열 다음에 물리적 연산자가 결정한 설명이 나올 경우도 있습니다. 자세한 내용은 논리 물리 연산자 참조를 참조하십시오.

StmtId

현재 일괄 처리에 있는 문의 수입니다. (몇번째 쿼리에 대한 통계인지)

NodeId

현재 쿼리의 노드 ID입니다. (현재 노드의 식별값)

Parent

부모 단계의 노드 ID입니다 (이 값이 같은 것 끼리, 같은 depth라고 생각하면 된다)

PhysicalOp

노드에 대한 물리적 구현 알고리즘입니다. PLAN_ROWS 형식의 행에만 해당됩니다.

LogicalOp

이 노드가 나타내는 관계형 대수 연산자입니다. PLAN_ROWS 형식의 행에만 해당됩니다.

Argument

수행되는 작업에 대한 추가 정보를 제공합니다. 물리적 연산자에 따라 이 열의 내용이 달라집니다.

DefinedValues

이 연산자가 사용하는 값에 대한 쉼표로 구분된 목록을 포함합니다. 이 값은 현재 쿼리에 있었던 계산된 식(: SELECT 목록이나 WHERE 절에 있음)이거나 이 쿼리를 처리하기 위해 쿼리 프로세서에서 사용한 내부 값입니다. 쿼리 내의 어디에서든 정의된 이 값이 참조될 수 있습니다. PLAN_ROWS 형식의 행에만 해당됩니다.

EstimateRows

이 연산자가 생성한 출력의 예상 행 수입니다. PLAN_ROWS 형식의 행에만 해당됩니다.

EstimateIO

작업에 대한 예상 I/O 비용입니다. PLAN_ROWS 형식의 행에만 해당됩니다.

EstimateCPU

이 연산자에 대한 예상 CPU 비용입니다. PLAN_ROWS 형식의 행에만 해당됩니다.

AvgRowSize

이 연산자를 통해 통과되는 행의 예상 평균 행 크기(바이트)입니다.

TotalSubtreeCost

이 작업 및 모든 자식 작업에 대한 예상(누적) 비용입니다.

OutputList

현재 작업에서 예상하고 있는 열에 대한 쉼표로 구분된 목록을 포함합니다.

Warnings

현재 작업과 연관된 경고 메시지에 대한 쉼표로 구분된 목록을 포함합니다. 경고 메시지에 열 목록과 함께 "NO STATS:()" 문자열이 포함될 경우도 있습니다. 이 경고 메시지는 쿼리 최적화 프로그램이 이 열의 통계에 기초하여 결정을 내리려고 했지만 사용 가능한 통계가 없었음을 나타냅니다. 따라서 쿼리 최적화 프로그램이 추측을 해야 했고 결과적으로 비효율적인 쿼리 계획을 선택했을 수도 있습니다. 쿼리 최적화 프로그램이 더 효율적인 쿼리 계획을 선택할 수 있도록 통계를 만들거나 업데이트하는 방법은 UPDATE STATISTICS를 참조하십시오. 어떤 경우에는 이 열에 조인 조건자 없이 조인(테이블을 수반하는)이 일어났음을 나타내는 "MISSING JOIN PREDICATE" 문자열이 포함되기도 합니다. 실수로 조인 조건자를 삭제하면 예상보다 실행 시간이 긴 쿼리가 만들어지고 큰 결과 집합이 반환됩니다. 이 경고가 나타나면 조인 조건자를 의도적으로 사용하지 않았는지 확인하십시오.

Type

노드 유형. 각 쿼리의 부모 노드에 대해서는 노드 유형이 Transact-SQL 문 유형(: SELECT, INSERT, EXECUTE )입니다. 실행 계획을 나타내는 하위 노드에 대해서는 PLAN_ROW 유형입니다.

Parallel

0 = 연산자가 병렬로 실행되지 않습니다.

1 = 연산자가 병렬로 실행됩니다.

EstimateExecutions

현재 쿼리를 실행하는 동안 이 연산자가 실행될 예상 횟수입니다.



Physical Op & Losical Op 에 사용되는 연산자
1) Bookmark Lookup 실행 계획 연산자
Bookmark Lookup 연산자는 책갈피(행 ID 또는 클러스터링 키)를 사용하여 테이블이나 클러스터형 인덱스에서 해당 행을 조회합니다. Argument 열에는 테이블이나 클러스터형 인덱스에서 행을 조회할 때 사용하는 책갈피 레이블이 포함됩니다. Argument 열에는 행을 조회하는 테이블 또는 클러스터형 인덱스의 이름도 포함됩니다. WITH PREFETCH 절이 Argument 열에 나타나는 경우에 쿼리 프로세서에서는 테이블 또는 클러스터형 인덱스에서 책갈피를 조회할 때 비동기 사전 인출(미리 읽기)을 사용하는 것을 최적의 방법으로 결정합니다.

SQL Server 2008에서는 Bookmark Lookup이 사용되지 않습니다. 대신 Clustered Index Seek 및 RID Lookup이 책갈피 조회 기능을 제공합니다. Key Lookup 연산자도 이 기능을 제공합니다.

Clustered Index는 DATA PAGE가 Index Leaf Level 에 존재를 한다.
Non-Clustered Index의 DATA PAGE는 Index Leaf Level에 존재하지 않는다.

즉, Non-Clustered Index로 해당 값을 Index Seek로 검색을 하였어도 출력될 값을 찾기 위해서는 해당 DATA PAGE 까지 찾아 들어가야 하는것이다. 그래서 MS-SQL 2000에서는 Bookmark lookup이라는것이 발생하는것이다.

2) RID Lookup 실행 계획 연산자
RID Lookup은 제공된 RID(행 식별자)를 사용하여 힙을 조회하는 책갈피 조회입니다. Argument 열은  테이블의 행을 조회하는 데 사용되는 책갈피 레이블 및 행을 조회할 테이블의 이름을 포함합니다.

RID Lookup은 항상 NESTED LOOP JOIN과 함께 사용됩니다.
RID Lookup은 물리 연산자입니다.

이제 RID Lookup을 실제 재현해보기 위해서 Test_Lookup Table에 Unique Non-Clustered Index를 만들어 보겠다.
왜 굳이 Non-Clustered Index를 만드느냐? RID Lookup은 Heap Table에서 만 일어난다. Heap Table은 Clustered Index가 없는 Table을 지칭한다. 그럼 왜 또 구지 Unique Type으로 만드냐? Unique Type이 아니면 Query 실행 될때 Table Scan이 일어난다

3) Key Lookup 실행 계획 연산자
SQL Server 2005 서비스 팩 2에 새로 추가된 Key Lookup 연산자는 클러스터형 인덱스가 있는 테이블의 책갈피 조회입니다. Argument 열에는 클러스터형 인덱스의 이름과 클러스터형 인덱스에서 행을 조회할 때 사용되는 클러스터링 키가 포함됩니다. Key Lookup은 항상 Nested Loops 연산자와 함께 사용됩니다. WITH PREFETCH 절이 Argument 열에 나타나는 경우에 쿼리 프로세서에서는 클러스터형 인덱스에서 책갈피를 조회할 때 비동기 사전 인출(미리 읽기)을 사용하는 것을 최적의 방법으로 결정합니다. 

Table에서 KEY Lookup을 발생시키려면 3가지 조건이 필요하다.
첫번째, Clustered Index가 존재해야 한다.
두번째, 검색될 Non-Clustered Index가 존재해야 한다.
세번째, Index가 걸리지 않은 출력될 목록이 있어야 한다.

posted by 방랑군 2009. 9. 30. 13:37

 저장프로시저가 좋다고 지랄하는 놈들한테 넌지시 말한번 꺼낼수 있는 좋은 아티클..^^;

이분한테 참 감사하고 싶다...

그래도, 나도 싫은 DB 에 잘 몰라서다... 우기기는 싫거든....


참조 : http://resisa.tistory.com/55


"저장 프로시저 사용해보셨나요?" 어떤 분이 저에게 이렇게 묻는다면 저는 "아니요. "라고 대답을 할 것입니다. 안타깝게도(?) 프로젝트에서 전 저장 프로시저를 사용해보지 못했습니다. 그래서 전 저장프로시저에 대해서 잘모릅니다. 이번에는 진짜로 제가 받은 질문입니다. 개발시에 Inline쿼리와 저장 프로시저중에 선택을 해야 한다면 어떤 것을 선택할 것이냐는 질문입니다. 개발인력이 많다면 전 Inline쿼리를 사용할 것이라고 대답했습니다. 개발인력이 많다는 것은 제 개인적인 생각이지만 저처럼 저장 프로시저를 사용해보지 못한 사람들도 많을 것이라는 생각때문이였고 저장 프로시저에 대해서 제 자신이 잘 모르기 때문입니다. 그 분이 다시 저에게 이런 말을 했습니다. 저장 프로시저는 컴파일이 된 이후에 다음에 사용할 경우에는 캐쉬된 상태로 사용되기 때문에 당연히 저장 프로시저를 사용해야 된다는 말이였습니다. 그래서 제가 정적SQL인지 동적SQL인지 명칭이 확실하지는 않지만 파라미터를 사용하는 쿼리는(MSSQL @문자로 오라클은 :문자로 받을 경우) 컴파일을 한번만 한다고 말했지만 그 분은 아니라고 하셨습니다. 그럼 한 번 확인해볼까요?

테스트 환경은 운영체제는 Vista, DB MSSQL2005이며 System.Data.SqlClient를 사용해서 확인해보도록 하겠습니다. 코드는 아래와 같습니다.
1.
파라미터 없는 SQL

string ConnStr = "Data Source=(local);Initial Catalog=TestDB;Persist Security Info=True;User ID=sa;Password=dsdvp";

 

string query = " SELECT * FROM Student WHERE ID = '2' ";

SqlConnection conn = new SqlConnection(ConnStr);

 

SqlCommand cmd = new SqlCommand(query, conn);

conn.Open();

 

cmd.ExecuteNonQuery();

conn.Close();


2. 파라미터 있는 SQL

string ConnStr = "Data Source=(local);Initial Catalog=TestDB;Persist Security Info=True;User ID=sa;Password=dsdvp";

 

string query = " SELECT * FROM Student WHERE ID = @ID ";

SqlConnection conn = new SqlConnection(ConnStr);

 

SqlCommand cmd = new SqlCommand(query, conn);

SqlParameter param = new SqlParameter("ID", "2");

 

cmd.Parameters.Add(param);

conn.Open();

 

cmd.ExecuteNonQuery();

conn.Close();


3. 저장 프로시저

string ConnStr = "Data Source=(local);Initial Catalog=TestDB;Persist Security Info=True;User ID=sa;Password=dsdvp";

SqlConnection conn = new SqlConnection(ConnStr);

 

SqlCommand cmd = new SqlCommand();

cmd.Connection = conn;

cmd.CommandType = CommandType.StoredProcedure;

cmd.CommandText = "TestProc";

conn.Open();

 

cmd.ExecuteNonQuery();

conn.Close();

=> Inline쿼리나 저장 프로시저가 컴파일되는지의 여부를 알기 위해서 이전에 SQL 튜닝교육을 받았던 문서를 보다가 운영체제에서 제공해주는 XP에서는 관리도구-성능 Vista에서는 관리도구-안정성 및 성능모니터를 사용하였습니다. 성능모니터를 하기 위해서는 카운터를 추가해주어야 합니다. SQL Server:SQL Statstics에서 SQL Compilations/sec SQL Re-Complilations/sec를 추가해주고 배율을 좀 더 확인하기 쉽도록 1에서 10으로 변경해준 후에 위의 구문 3개를 실행해보았습니다.
먼저 1, 2, 3번을 차례대로 실행했을 경우의 화면입니다.

=> 파라미터가 없는 SQL이 가장 높게 나타나는 것을 볼 수 있고 파라미터가 있는 SQL과 저장 프로시저를 동일하게 나타납니다. 이후의 1, 2, 3번 어떤 것을 계속 실행하여도 다시 컴파일 되는 것을 볼 수 없습니다. 혹시나 1, 2, 3번을 실행한 순서에 관계가 있나 싶어 서비스에서 SQL를 내렸다 다시 올려 번갈아 가면서 실행해 보았지만 순서만 달라질 뿐 위의 결과와 똑같은 것을 확인할 수 있었습니다. 여기서 Inline쿼리도 저장 프로시저와 마찬가지로 한번만 컴파일 된다는 것을 알 수 있습니다. 저는 2, 3번만 컴파일이 한번 될 줄 알았는데 1번도 컴파일은 한번만 됩니다. 그런데 왜 1번만 컴파일 과정에서 높게 나타날까요? SQL Server Profiler로 알아보도록 하겠습니다.

새추적를 누르고 '모든 이벤트 표시'를 체크해준 후에 Stored Procedures TSQL의 모든 이벤트를 체크해줍니다그리고 1, 2, 3번을 실행시킨 화면입니다.
1.
파라미터 없는 SQL

2. 파라미터 있는 SQL

3. 저장 프로시저

=> 차이가 보이시나요? 1번에서는 SP:CacheInsert가 두 번 되는 것을 확인하실 수 있습니다. 그래서 2번이나 3번보다 컴파일시에 더 높게 나타나는 것입니다. 다음은 컴파일 된 이후에 1번을 실행시킨 것을 추적한 화면입니다.

=> SP:CacheHit가 일어나는 것으로 보아 그냥 날리는 Inline 쿼리의 경우에도 캐쉬가 되는 것을 알 수있습니다. 더군다나 파라미터가 있는 SQL의 경우에는 마치 저장 프로시저처럼 실행이 되는 것도 알 수 있었습니다컴파일도 캐쉬도 Inline쿼리가 저장 프로시저보다 사용하기에 나쁜 이유는 되지 않는 것 같습니다.

다음은 제가 SQL 튜닝 교육을 받았던 강사님의 홈페이지에 대한 저장 프로시저에 대한 내용입니다.
http://www.sqlworld.pe.kr/

1. 저장 프로시져에 사용된 모든 구문이 미리 분석되어 최적화된 후 처음 수행시 메모리에 올려져 이후에 사용 될때는 메모리에 올려진 내용이 수행되므로 속도가 월등히 빠릅니다.
2. 복잡한 퀴리문을 네트워크를 통하여 서버로 보낼 필요가 없이, 단지 저장 프로시져를 호출하는 간단한 내용만 서버로 전달되므로 네트워크 트래픽이 감소됩니다.
3. 특정 테이블에 대한 권한이 없는 사용자 계정에 저장 프로시져를 수행 할 수 있는 권한을 주어 필요한 작업을 할 수있게 할 수 있으므로 보안성을 높일 수 있습니다.
4. 특정 기능을 수행하는 저장 프로시져를 만들어 두면 여러 응용프로그램에서 이를 활용 할 수 있습니다. , 특정처리를 위한 모듈화작업이 가능합니다. 모듈화가 되어 있으므로 응용프로그램 전체의 수정없이 해당 저장 프로시져만을 수정하여 원하는 기능 구현을 할수 있습니다.

=> 1번의 경우 월등히 빠르다는 위에서 제가 테스트한 결과와 조금은 다른 내용으로 저에게 질문을 하신 분과 같은 의견입니다. 2번의 경우가 제가 표현을 못했던 가장 중요한 이유입니다. 복잡한 쿼리문을 네트워크로 전송하는 것보다는 저장 프로시저의 이름만 넘기는 것이 당연히 네트워크의 부하를 주지 않을 것입니다하지만 이 경우도 일반적인 응용 프로그램이 아닌 웹 프로그램이면서 웹서버와 DB가 같이 돌고 있는 경우라면 그렇게 큰 차이가 있을까요? 3번의 경우에는 응용 프로그램 자체에서 권한 관리를 한다면 굳이 상관없어 보입니다. 4번이 인라인과 저장 프로시저를 어떤 것을 선택해야 하는지의 가장 중요한 지표가 되는 것 같습니다. 쿼리 부분을 프로그램에서 관리할 것인지 DB안에 저장 프로시저로 관리할 것인지의 여부입니다.

일반적으로 비지니스 로직 레이어에서 트랜잭션을 발생시킵니다. 저장 프로시저를 사용하면 저장 프로시저안에서 트랜잭션 처리를 하게 되고 실질적으로 비지니스 로직 레이어가 의미가 없어져 버립니다. 하지만 이 트랜잭션이라는 것이 단순히 DB에 대한 트랜잭션만 있어야 하는 것일까요? 파일이나 레지스트리에 대한 모든 것에 트랜잭션으로 한꺼번에 처리하고 싶을 경우에도 저장 프로시저로 모든 것이 가능할까란 생각이 제일 먼저 듭니다. 또한 비지니스 로직에 계산 로직 등 복잡한 로직이 들어간 상태에서 트랜잭션 처리를 해야 한다면 저장 프로시저에서는 어떻게 처리할까요다시 한번 말씀드리지만 저는 저장 프로시저를 싫어하는 사람이 아니라 저장 프로시저에 대해서 잘 모르는 사람입니다. 아마 정답은 상황에 맞게 Inline쿼리와 저장 프로시저를 적절하게(?) 사용하는 것 아닐까요?

저작자 표시



'IT > DB' 카테고리의 다른 글

인덱스 정리  (0) 2009.09.30
인덱스가 있지만 인덱스를 안 타는 경우  (0) 2009.09.30
MS-SQL 실행 계획 확인  (0) 2009.09.30
SUBQUERY와 INLINE-VIEW의 차이  (1) 2009.09.30
[MS SQL] ldf 파일 사이즈 줄이기 또는 삭제하기  (0) 2009.09.28
posted by 방랑군 2009. 9. 30. 13:31

참조 : http://blog.naver.com/addibuddi?Redirect=Log&logNo=16037753


SUBQUERY와 INLINE-VIEW가 표현되는 방식이 달라....

의미상으로도 다른줄 알았는데...

INLINE-VIEW자체도 SUBQUERY의 하나의 방식이라는 군요..

 

및에는 참조~

 


☞ Subquery란?  
 
 ◈ SUBQUERY는 다른 하나의 SQL 문장의 절에 NESTEDED된 SELECT 문장 입니다.

 ◈ SELECT, UPDATE, DELETE, INSERT와 같은 DML문과 CREATE TABLE 또는 VIEW에서
     이용 될 수 있습니다.

 ◈ 알려지지 않은 조건에 근거한 값들을 검색하는 SELECT 문장을 작성하는데 유용 합니다.

 ◈ SUBQUERY는 MAIN QUERY가 실행되기 이전에 한번 실행 됩니다.


☞ Guidelines

 ◈ SUBQUERY는 괄호로 묶어야 합니다.

 ◈ 두 종류의 비교 연산자들이 SUBQUERY에 사용 됩니다.
    - 단일 행 연산자( =,>, >=, <, <=, <>, != )
    - 복수 행 연산자( IN, NOT IN, ANY, ALL, EXISTS )

 ◈ SUBQUERY는 연산자의 오른쪽에 나타나야 합니다.


☞ SUBQUERY의 유형
 
 ◈ 단일 행(Sing-Row) 서브쿼리 : SELECT문장으로부터 오직 하나의 행만을 검색하는 질의입니다

 ◈ 다중 행(Multiple-Row) 서브쿼리 : SELECT문장으로부터 하나 이상의 행을 검색하는 질의입니다

 ◈ 다중 열(Multiple-Column) 서브쿼리 : SELECT문장으로부터 하나 이상의 컬럼을 검색하는
    질의입니다

 ◈ FROM절상의 서브쿼리(INLINE VIEW) : FROM절상에 오는 서브쿼리로 VIEW처럼 작용 합니다.

 ◈ 상관관계 서브 쿼리 : 바깥쪽 쿼리의 컬럼 중의 하나가 안쪽 서브쿼리의 조건에 이용되는
     처리 방식 입니다.


☞ FROM절상의 서브쿼리(INLINE VIEW)

 ◈ SUBQUERY는 FROM절에서도 사용이 가능 합니다.

 ◈ INLINE VIEW란 FROM절상에 오는 서브쿼리로 VIEW처럼 작용 합니다.

 
예제)급여가 20부서의 평균 급여보다 크고 사원을 관리하는 사원으로서 20부서에 속하지 않은
      사원의 정보를 보여주는 SQL문 입니다.
 
SQL>SELECT b.empno,b.ename,b.job,b.sal, b.deptno
        FROM (SELECT empno
                  FROM emp  
                  WHERE sal >(SELECT AVG(sal) FROM emp WHERE deptno = 20))
a, emp b
        WHERE a.empno = b.empno
             AND b.mgr is NOT NULL
            AND b.deptno != 20
 
     EMPNO ENAME      JOB              SAL     DEPTNO
---------- ---------- --------- ---------- ----------
      7698 BLAKE      MANAGER         2850         30
      7782 CLARK      MANAGER         2450         10

 

 


☞ 다중 열(Multiple-Column) 서브쿼리

 ◈ 다중 열 서브쿼리란 서브쿼리의 결과값이 두개 이상의 컬럼을 반환하는 서브쿼리 입니다.


☞ Pairwise(쌍비교) Subquery
 
 - 서브쿼리가 한번 실행되면서 모든 조건을 검색해서 주 쿼리로 넘겨 줍니다.
 
SQL> SELECT empno, sal, deptno
        FROM emp
        WHERE (sal, deptno) IN ( SELECT sal, deptno
                                            FROM emp
                                            WHERE deptno = 30
                                                 AND comm is NOT NULL )
;
                             
     EMPNO        SAL     DEPTNO
---------- ---------- ----------
      7521       1250         30
      7654       1250         30
      7844       1500         30
      7499       1600         30



☞ Nonpairwise(비쌍비교) Subquery

 - 서브쿼리가 여러 조건별로 사용 되어서 결과값을 주 쿼리로 넘겨 줍니다.
 
SQL>SELECT empno, sal, deptno
        FROM emp
        WHERE sal IN ( SELECT sal
                              FROM emp
                              WHERE deptno = 30
                                   AND comm is NOT NULL )

            AND deptno  IN ( SELECT deptno
                                    FROM emp
                                    WHERE deptno = 30
                                         AND comm is NOT NULL );


     EMPNO        SAL     DEPTNO
---------- ---------- ----------
      7521       1250         30
      7654       1250         30
      7844       1500         30
      7499       1600         30



☞ Null Values in a Subquery

   - 서브쿼리에서 null값이 반환되면 주 쿼리 에서는 어떠한 행도 반환되지 않습니다.

 

☞ 다중 행(Multiple-Row) 서브쿼리

 ◈ 하나 이상의 행을 RETURN하는 SUBQUERY를 다중 행 SUBQUERY라고 합니다.

 ◈ 복수 행 연산자(IN, NOT IN, ANY, ALL, EXISTS)를 사용 할 수 있습니다.


☞ IN 연산자의 사용 예제
 
  부서별로 가장 급여를 많이 받는 사원의 정보를 출력하는 예제
 
SQL>SELECT empno,ename,sal,deptno  
        FROM emp
        WHERE sal IN (SELECT MAX(sal)
                              FROM emp
                              GROUP BY deptno)
;

     EMPNO ENAME             SAL     DEPTNO
---------- ----------   ---------- ----------
      7698 BLAKE             2850           30
      7788 SCOTT            3000           20
      7902 FORD              3000           20
      7839 KING               5000           10



☞ ANY 연산자의 사용 예제

  ANY연산자는 서브쿼리의 결과값중 어느 하나의 값이라도 만족이 되면 결과값을 반환 합니다.

SQL>SELECT ename, sal
        FROM emp
        WHERE deptno != 20
             AND sal > ANY(SELECT sal FROM emp WHERE job='SALESMAN');  
 
ENAME             SAL
---------- ----------
ALLEN            1600
BLAKE            2850
CLARK            2450
KING              5000
TURNER          1500
MILLER           1300

6 개의 행이 선택되었습니다.



☞ ALL 연산자의 사용 예제

  ALL연산자는 서브쿼리의 결과값중 모든 결과 값이 만족 되야만 결과값을 반환 합니다.
 
SQL>SELECT ename, sal
        FROM emp
        WHERE deptno != 20
             AND sal > ALL(SELECT sal FROM emp WHERE job='SALESMAN');
 
ENAME             SAL
---------- ----------
BLAKE            2850
CLARK            2450
KING             5000

3 개의 행이 선택되었습니다.



☞ EXISTS 연산자의 사용 예제

 - EXISTS 연산자를 사용하면 서브쿼리의 데이터가 존재하는가의 여부를 먼저 따져 존재하는
   값들만을 결과로 반환해 줍니다.
 - SUBQUERY에서 적어도 1개의 행을 RETURN하면 논리식은 참이고 그렇지 않으면 거짓 입니다.

예제)사원을 관리할 수 있는 사원의 정보를 보여 줍니다.
 
SQL>SELECT empno, ename, sal
        FROM emp e
        WHERE EXISTS (SELECT empno FROM emp WHERE e.empno = mgr) 

     EMPNO ENAME             SAL
---------- ---------- ----------
      7566 JONES             2975
      7698 BLAKE             2850
      7782 CLARK             2450
      7788 SCOTT            3000
      7839 KING               5000
      7902 FORD              3000
 
6 개의 행이 선택되었습니다.

  ================================================
    * Oracle Community OracleClub.com
    * http://www.oracleclub.com
    * http://www.oramaster.net
    * 운영자 : 김정식 (oramaster _at_ empal.com)
  ================================================ 



posted by 방랑군 2009. 9. 30. 10:09
영어사전의 뜻
singleton
- 1 하나씩 일어나는 일, 홀로인 것, 독자(獨子) 2 (카드놀이의) 한 장 패(의 수)


뜻 : 
개체가 하나의 인스턴스를 가지는것을 보장하며, 그 개체를 전역적인 면에서 접근하는 것을 보장함.
생성된 인스턴스를 어디서든지 접근할 수 있게 하기 위한 패턴

KEY POINT :
 멀티스레딩 환경에서 여러개의 개체가 만들어 질 수 있다.
그래서, 동기화 한다.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;


namespace Console_Patten

{


    /// <summary>

    /// MySingleton을 실행하기 위한 클래스

    /// </summary>

    class Program

    {

        static void Main(string[] args)

        {

            MySingleton objTest1 = null;  //첫번째 인스턴스

            MySingleton objTest2 = null;  //두번째 인스턴스

            int i = 0;


            //첫번째 object에 MySingleton 인스턴스를 전달하고 시간을 출력해 본다.

            objTest1 = MySingleton.GetInstance();

            System.Console.WriteLine("인스턴스 호출 = " + System.DateTime.Now.ToLongTimeString()

                                        + ";" + "objTest1.TimeOfBirth() = " + objTest1.TimeOfBirth);

            //시간 지연을 위한 코드 *본인PC에서는 약 2초의 지연이 생김*

            for (i = 1; i < 1500000000; i++)

            {


            }


            //두번째 object에 MySingleton 인스턴스를 전달하고 시간을 출력해 본다.

            objTest2 = MySingleton.GetInstance();

            System.Console.WriteLine("인스턴스 호출 = " + System.DateTime.Now.ToLongTimeString()

                + ";" + "objTest2.TimeOfBirth() = " + objTest2.TimeOfBirth);

            

            //두개의 object의 생성시간이 같은것을 볼 수 있다.

            System.Console.ReadLine();

        }

    }


    /*

 static 멤버인 m_Instance는 객체의 단일 공유 인스턴스이다. 

 이 단일 공유 인스턴스는 공개함수인 GetInstance()에 의해 참조값이 반환된다.

 GetInstance는 m_Instace가 null인 경우에만 m_Instance를 생성하므로서 단일성을 유지한다

 생성자는 Private로 만들어 숨겨져 있다. 


 m_TimeOfBirth는 단지 테스트를 위한 멤버이다. 이것은 이 인스턴스가 생성된 시간을 가지고 있다. 

*/

    /// <summary>

    /// 유일성을 유지하고 싶은 클래스

    /// </summary>

    public class MySingleton

    {


        private static MySingleton m_Instanace = null;

        // 쓰레드로부터 안전한 인스턴스 생성을 위해 Mutex사용

        private static System.Threading.Mutex m_Mutex = new System.Threading.Mutex();

        #region 예제를 위한 부분 실사용중에는 별로 필요치 않음

        private static string m_TimeOfBirth = "";

        

        public string TimeOfBirth

        {

            get

            {

                return m_TimeOfBirth;

            }

        }

        #endregion

        /// <summary>

        /// 생성자 Private으로 존재한다. 필요하지 않은것은 아니며 단지 숨겨져 있을 뿐이다.

        /// </summary>

        private MySingleton()

        {

            System.Console.WriteLine("Singleton 생성시간 = " + System.DateTime.Now.ToLongTimeString());

            m_TimeOfBirth = System.DateTime.Now.ToLongTimeString();

        }

        /// <summary>

        /// 인스턴스를 리턴하는 함수이며 인스턴스가 null인 경우에만 인스턴스를 생성한다.

        /// </summary>

        /// <returns>MySingleton 인스턴스 (this.m_Instance)</returns>

        public static MySingleton GetInstance()

        {

            m_Mutex.WaitOne();

            if (m_Instanace == null)

            {

                m_Instanace = new MySingleton();

            }

            m_Mutex.ReleaseMutex();

            return m_Instanace;

        }

    }

}






야설:
singletone은 한번에 하나씩의 패만 보여준다는 의미를 가지고 있다. 좀더 일반적으로는 한번에 하나의 사건만 일어나도록 한다라는 의미로 해석할 수 있을 것 같다.

소프트웨어 엔지니어링 영역에서의 singletone은 객체지향프로그래밍시 클래스가 단하나의 사건, 즉 다시 말해서 단 하나의 인스턴스만을 가지도록 하는 패턴이다. 이 패턴은 주로 중요한자원을 관리하고자 할때, 다수의 인스턴스가 생성되지 않도록 만들어준다. 예컨데, 한번에 하나의 인스턴스만이 데이터베이스에 연결되는게 보장받기를 원하는 경우에 사용할 수 있을 것이다.
singletone은 다른 패턴들과도 어울려서 사용할 수 있는데, 다음과 같은 경우들이다.
  1. facade 객체는 단지 하나의 객체만이 요구되는데, 이를 보장하기 위해서 singletone을 사용할 수 있다. 예를들어 컴퓨터를 가동시키는 facade 클래스가 있다고 가정해보자. 컴퓨터를 가동시키기 위한 여러가지 공정들 즉 cpu freeze, memory load, cpu jump, cpu execute은 단지 하나의 객체가 생성되어서 수행되는 것을 보장해야 할 것이다.
  2. 때때로 singleton 패턴은 전역변수를 제한하기 위해서 사용되기도 한다. 전역변수를 모아서 하나의 single 클래스에 담아두는 방식으로 사용한다. 전역변수문제를 해결하기 위한 용도로 사용할 경우에 singleton 패턴자체가 전역클래스가 된다는 문제점이 있지만, namespace 충동물제를 해결하고 전역변수를 한 지점에서 관리할 수 있다는 것만으로도 singleton 패턴은 충분히 역할을 해낼 것이다.

'GET > Patten' 카테고리의 다른 글

prototype 패턴 (쌍둥이) 과 singleton 패턴  (0) 2009.09.30
posted by 방랑군 2009. 9. 29. 13:18


참조 : http://kingcrap.com/entry/Hands-on-Labs-for-EL-41-and-Unity-12



Enterprise Library 4.1 (EL) 과 Unity Application Block 1.2 (Unity) 에 대한 Hands-on Lab이 공개됐다. 국내 닷넷 개발 진영에도 범용 개발 프레임웍에 대한 관심이 고조되고 있고, 점차 많은 적용 사례가 공유되어 신규 개발에 힘을 실어주고 있는 시점에 EL과 Unity에 대한 HOL의 발표는 참으로 적절한 타이밍이라 여겨진다.

Enterprise Library는 이름이 의미하듯이 엔터프라이즈 애플리케이션 개발에 늘 고려하는, 즉 cross-cutting concern이라할 수 있는 기능을 모아 쉽게 적용할 수 있게 만든 라이브러리 모음집이다.

image

현재 EL 4.1에 포함되어 있는 Application block들로는 PIAB (Policy Injection Application Block), Logging, Caching, Cryptography, Data Access, Exception handling, Security, Validation 그리고 Unity가 있다. EL 4.1 HOL은 바로 이들 각각에 대한 HOL을 C#과 VB로 제공하여 쉽게 따라하며 익힐 수 있게 구성되어 있다.

image

좌측 그림 가운데 Interception (w/ PIAB and Unity), Unity, Validation은 새롭게 추가된 것들이며, 그외 나머지 HOL은 이전 버전의 것을 업데이트한 것이다.

EL과 Unity가 호스팅되고 있는 Codeplex를 방문하면 좀 더 상세한 정보를 알아 볼수 있다.
EL 4.1 ": http://www.codeplex.com/entlib
Unity : http://www.codeplex.com/unity

각각의 HOL의 다운로드 위치는 다음과 같다.
EL 4.1 HOL
Unity 1.2 HOL

MSDN에서도 EL과 Unity에 대한 상세한 정보를 찾을 수 있다.
EL 4.1
Unity 1.2

참고로 EL과 Unity를 포함하여 p&p에서 제공하는 각종 asset들을 활용하여 개발자 생산성이 40%까지 향상될 수 있다는 조사 보고서도 여기서 살펴볼 수 있다.

 

p&p 팀에서는 또한 Enterprise Library 다음 버전에 담고 싶은 기능에 대한 온라인 설문 조사를 진행하고 있다. 평소에 담고 싶었던 내용이 있었다면 한번쯤 의견을 전달하는 것도 좋을 것으로 생각된다.

EntLib_voting_2



'GET > FrameWork' 카테고리의 다른 글

방랑이가 생각하는 Spring.NET...  (0) 2009.10.06
Spring.NET - 레퍼런스 문서 한글화 사이트..  (0) 2009.09.30
객체의 생명주기  (0) 2009.09.30
Spring 컨테이너와 아키텍처 구성  (0) 2009.09.30
Spring.NET 생명 주기  (0) 2009.09.30
posted by 방랑군 2009. 9. 29. 13:13

참조 : http://kingcrap.com/entry/닷넷에서-native-dll-사용하기



닷넷에서 C/C++로 작성된 dll을 사용하고자 할 경우 다음과 같은 방법이 있다.

1. 일반적인 native dll의 경우 - P/Invoke (Platform Invoke)를 써서 직접 호출
닷넷에서 Win32 API를 호출하거나 C/C++로 작성된 native dll을 호출할 경우, native dll이 제공하는 메소드의 signature나 타입에 대해 닷넷에서 인식하고 호출할 수 있도록 이에 대한 선언을 해야 한다. 크게 보면 세 단계로 구성되는데, 첫째 DllImport하여 필요한 dll 로딩하는 부분, 둘째 원하는 메소드 signature를 extern으로 선언하는 부분(즉, 이 메소드가 외부 native dll에서 정의되어 있다고 선언하는 부분), 마지막으로 이 메소드를 호출하여 원하는 값을 취하는 부분으로 되어 있다.

Win32 API에 대한 선언을 일일이 기억하기란 쉽지 않기 때문에 웹에 이에 대한 데이터베이스 형태의 wiki로서 PInvoke.net이 존재한다. 아래 화면은 http://www.pinvoke.net 에서 볼 수 있다.pinvoke 
아울러 PInvoke.net에서는 Visual Studio 2005에 대한 플러그 인을 제공하여 무료로 다운받아 설치할 수 있으며 아래 그림에서 처럼 VS내에서 원하는 선언문을 검색하여 바로 붙여 넣을 수 있다.
image 

이보다 좀 더 나은 방식으로 간단한 애플리케이션 형태의  AppViewer가 존재하여 편리하게 원하는 API에 대한 선언문을 사용할 수 있다. 아래 그림에서 보듯이 다양한 언어, 심지어 delphi나 MASM에서 사용할 수 있는 기능까지 제공하고 있다.
 image image

자바에서도 이와 동일한 세 단계 방식의 호출 방법이 있는데, JNI (Java Native Interface)라고 부른다. System.loadLibrary()하여 dll을 메모리에 올리는 부분, 호출하고자 하는 메소드의 signature를 native라는 modifier를 써서 선언하는 부분(역시 이 메소드의 구현은 native하게 외부에 정의되어 있다고 선언하는 부분), 마지막으로 이 메소드를 호출하는 부분으로 구성된다. 자바가 호출하는 메소드를 C/C++에서 구현하기 위해서는 각 언어에 맞는 헤더파일이 필요한데 이를 위해 javah -jni 명령어를 써서 *.h 파일을 생성하며 이렇게 생성된 *.h를 C/C++에서 include하여 개발하는 과정을 거치게 된다.

2. COM 서버 접근 - RCW (Runtime-Callable Wrapper)를 이용하는 방법
COM 객체에 대한 wrapper를 만들어서 닷넷에서는 마치 일반적인 닷넷 객체를 호출하듯 프로그래밍할 수 있도록 지원하는 방법이다. Visual Studio에서 Add Reference기능을 클릭하며 아래에서 처럼 COM 컴포넌트를 선택할 수 있으며 OK를 누르는 순간 레퍼런스가 추가되면서 이 COM 컴포넌트에 대한 닷넷 Wrapper가 생성된다. 생성되는 wrapper는 Interop.xxx.dll의 어셈블리가 된다. 따라서 개발자는 닷넷 프로그래밍 하는 방식으로 COM 객체를 생성하고 호출할 수 있게 된다.
image
Visual Studio를 사용하지 않는 경우에는 .NET SDK에 들어있는 TlbImp.exe 명령어를 사용하여 wrapper를 생성할 수도 있다.
COM 객체가 대단히 크거나 복잡할 경우 생성되는 Wrapper의 크기 또한 부담스러우며, COM 내부에서 사용하기 위해 만든 인터페이스를 wrapper에서 숨길 수 있는 방안도 없기 때문에, 간편하게 생성하여 사용할 수 있는 장점이 있지만  COM 객체의 특성에 따라 이 방법이 적합한지 한번쯤은 생각해 볼 필요가 있다. 아울러 사용이 끝난 COM 객체는 해당 wrapper가  GCed될 때까지 살아 있기 때문에, wrapper가  Garbage Collector에 의해 GCed될 때까지 기다리지 말고 System.Runtime.InteropServices.Marshal.ReleaseComObject()를 이용하여 즉시 해제해주는 것이 좋다.

Posted by 장현춘 
posted by 방랑군 2009. 9. 28. 08:54

Mssql의 로그파일인 LDF파일이 너무 커져버렸을때 용량 줄이기 방법

backup log 데이터베이스이름 with TRUNCATE_ONLY

DBCC SHRINKFILE (데이터베이스이름_Log, 10)

-숫자 10은 용량 !

한줄씩 실행하면 끝 !



+  testdb를 지정한다.(물론 다들 알고 계시겠죠.)
   줄이길 원하는 데이터베이스를 사용하겠다고 지정하는 겁니다.
use testdb

+ 로그파일의 정보를 확인합니다.

dbcc loginfo

+ 현재 지정된 디비가 사용하는 mdf 및 ldf파일의 경로, 이름 및 크기를 확인합니다.

exec sp_helpfile

+ 디비의 로그를 백업해 줍니다.

backup Log testdb to disk='f:\mssql\dbbackup\temp\testdb.bak'

 

+ 로그파일을 최소의 단위로 축소합니다.

backup log testdb with truncate_only


+ 로그파일을 삭제합니다.

backup log testdb with no_log

+ 로그파일을 10메가로 다시 생성합니다.

dbcc shrinkfile (testdb_log, 10)

+ mdf와 ldf파일 확인
exec sp_helpfile


+ 로그파일의 최대크기를 지정(물론 안해도 상관없습니다.)

alter database testdb

    modify file ( name = testdb_log, maxsize = 100 mb )


이상입니다.위에 축소나 삭제에 대한 사항은 원하시는 것을 선택해서 작업하시면 됩니다.

'IT > DB' 카테고리의 다른 글

인덱스 정리  (0) 2009.09.30
인덱스가 있지만 인덱스를 안 타는 경우  (0) 2009.09.30
MS-SQL 실행 계획 확인  (0) 2009.09.30
Inline 쿼리 VS 저장 프로시저  (0) 2009.09.30
SUBQUERY와 INLINE-VIEW의 차이  (1) 2009.09.30
posted by 방랑군 2009. 9. 24. 17:25



using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;


using System.Reflection;


namespace Console_AOP

{

    class Program

    {

        static void Main(string[] args)

        {   


            /// string으로  객체 타입을 얻는다

            /// - typeName :System.Type.AssemblyQualifiedName

            ///

            Type atype = Type.GetType("Console_AOP.TEST, Console_AOP");

            // == Type atype = Type.GetType("Console_AOP.TEST");


            object a = System.Activator.CreateInstance(atype);


            /// 1. CASTING

            /// 

            TEST test = (TEST)a;

            string strAddress = test.GetAddress2(2);


            Console.WriteLine(strAddress);


            /// 2. INVOKE

            /// 

            // 메소드 : A.GetAddress()를 호출한다.

            MethodInfo mi = atype.GetMethod("GetAddress");

            strAddress = (string) mi.Invoke(a, null);


            Console.WriteLine(strAddress);


            MethodInfo mi2 = atype.GetMethod("GetAddress2");

            strAddress = (string)mi2.Invoke(a, new object[] {1234});


            Console.WriteLine(strAddress);


            // 프로퍼티 : A. HP의 값을 호출한다.

            PropertyInfo pi = atype.GetProperty("HP");

            strAddress = (string)pi.GetValue(a, null);


            Console.WriteLine(strAddress);

        }

    }



    class TEST

    {

        // 필드

        public string _Name;


        // 프로퍼티

        public string HP

        {

            get { return _HP; }

            set { _HP = value; }

        }

        private string _HP;


        // 메소드

        public TEST()

        {

            _Name = "황승재";

            _HP = "016-647-0678";

        }


        public string GetAddress()

        {

            return "서울시 염창동 동아3차아파트";

        }


        public string GetAddress2(int _NO)

        {

            return "서울시 양천구 목2동 537-20";

        }

    }

}






'GET > Reflection' 카테고리의 다른 글

string 으로 동적 참조 2 & System.Activator.CreateInstance  (0) 2009.09.24
posted by 방랑군 2009. 9. 24. 17:02



using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;


namespace Console_AOP

{

    class Program

    {

        static void Main(string[] args)

        {   


            /// string으로  객체 타입을 얻는다

            /// - typeName :System.Type.AssemblyQualifiedName

            ///

            Type atype = Type.GetType("Console_AOP.TEST, Console_AOP");

            // == Type atype = Type.GetType("Console_AOP.TEST");


            object a = System.Activator.CreateInstance(atype);


            TEST test = (TEST)a;


            Console.Write(test.GetAddress(10));

        }

    }



    class TEST

    {


        public string _Name;

        public string _HP;


        public string GetAddress(int _NO)

        {

            return "서울시 양천구 목2동 537-20";

        }

    }

}



결과 : 
서울시 양천구 목2동 537-20
posted by 방랑군 2009. 9. 24. 15:48


1. http://devray.tistory.com/category/.NET%20Framework/C%23%20Common

'GET > Attribute' 카테고리의 다른 글

간단 예제.  (0) 2009.09.24
* Conditional 어트리뷰트 사용  (0) 2009.09.24
* DllImport 어트리뷰트  (0) 2009.09.24
Attrubute(어트리뷰트)  (0) 2009.09.24
Attribute Oriented Programming  (0) 2009.09.24
posted by 방랑군 2009. 9. 24. 15:48
1. Obsolete 어트리뷰트
2.  사용자 어트리뷰트

====================================

Program.cs 코딩

------------------------------------

using System;

public class 특성
{
    public static void Main(string[] args)
    {
        Say1();
        Say2();
    }
   
    /// <summary>
    /// 닷넷 1.0 버전
    /// </summary>
    // Say1()은 오래된버전으로 가정하고 Say2()만 사용하고싶을때..ObsoleteAttribute사용 Attribute생략가능~
    [Obsolete("현재 메서드는 오래된 버전이므로, Say2()를 사용하세요." , false)] // false는 경고만 띄워주고,true는 컴파일오류내줌
    public static void Say1()
    {
        Console.WriteLine("안녕");
    }
   
    /// <summary>
    /// 닷넷 2.0 버전 이상
    /// </summary>
    public static void Say2()
    {
        Console.WriteLine("안녕하세열");
    }
}

=========================================

사용자정의특성.cs 코딩

-------------------------------------------

using System;

namespace 사용자정의특성
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple=true)]
    // AttributeUsate = 특정 멤버에만 특성적용해줌, AllowMultiple=true : 다중지정 가능하게..
   
    public class AuthorAttribute : Attribute
    {
        public string name;
        public AuthorAttribute(string name)
        {
            this.name = name;
        }
    }
   
    [AuthorAttribute("RedPlus")]
    class 사용자정의특성
    {
        static void Main(string[] args)
        {
            Say();
            ShowMetaData();
        }
        // 특성정보 읽어오기
        private static void ShowMetaData()
        {
            System.Attribute[] attrs = System.Attribute.GetCustomAttributes(typeof(사용자정의특성));
           
            foreach (var attr in attrs)
         {
         // if (attr is AuthorAttribute)
            // {
         //     AuthorAttribute aa = ( AuthorAttribute)attr;
               //     Console.WriteLine("{0}", aa.name);
            // }
                AuthorAttribute aa = attr as AuthorAttribute;
                if (aa != null)
                {
                    Console.WriteLine("{0}", aa.name);
                }
         }
        }
        static void Say() { Console.WriteLine("안녕하세요."); }
    }
}

==============================================



'GET > Attribute' 카테고리의 다른 글

참고 사이트.  (0) 2009.09.24
* Conditional 어트리뷰트 사용  (0) 2009.09.24
* DllImport 어트리뷰트  (0) 2009.09.24
Attrubute(어트리뷰트)  (0) 2009.09.24
Attribute Oriented Programming  (0) 2009.09.24
posted by 방랑군 2009. 9. 24. 15:36
* Conditional 어트리뷰트 사용
#define DEBUG       //DEBUG   
//어트리뷰트 사용  
// #undef DEBUG     //어튜리뷰트 사용 해제
using System;  
using System.Diagnostics;
namespace CSharpStudy  
{  
       class  MainClass  
       {  
           [Conditional("DEBUG")]  
           public static void DebugPrint()  
           {  
              Console.WriteLine("Debug");  
           }   

           [STAThread]  
           static void Main(string[] args)  
           {  
              DebugPrint();  
           }
       }
}

C#코드는 디버깅을 지원하기 위해서 Conditonal 어트리뷰트를 사용 하며 지원을 합니다. Conditional 어트리뷰트는 사용자가 정의한 값에 의존해서 해당 메소드를 실행 시키도록 합니다. Conditional 어트리뷰트는 System.Diagnositcs 네임스페이스 안에 정의 되어 있습니다.

즉, #define을 설정해주지 않으면 실행 되지 않으며 설정시 실행이 됩니다.
Conditional 어트리뷰트는 클래스나 구조체 안에 있는 메소드에만 접착시킬 수 있다. 또한 그 메소드는 반드시 void형이어야 하며, 여러 Conditional어트리뷰트를 접착시키면 그중 하나만 위치지정 파라미터가 정의 되어 있어도 해당 메소드는 실행됩니다.

'GET > Attribute' 카테고리의 다른 글

참고 사이트.  (0) 2009.09.24
간단 예제.  (0) 2009.09.24
* DllImport 어트리뷰트  (0) 2009.09.24
Attrubute(어트리뷰트)  (0) 2009.09.24
Attribute Oriented Programming  (0) 2009.09.24
posted by 방랑군 2009. 9. 24. 15:35
* DllImport 어트리뷰트
   DllImport 어트리뷰트는 C#안에서 Unmanaged 코드를 사용 할 수 있게 합니다. Unmanaged 코드란 닷넷 환경밖에서 개발된 코드를 말하며 예를들면 DLL 파일들안에 컴파일된 표준 , DllImport 어트리뷰트는 System.Runtime.InteropServices 네임스페이스안에서 정의 되어있습니다.

using System  
using System.Runtime.InteopServices;  
class testClass  
{  
        [DllImport("User32.dll"]  
        public static extern int MessageBox(int h, string m, string c, int type);   

        static void Main()   
        {  
             MessageBox(0, "Hello world!", "C#", 0);  
        }  
}

다음은 Win32 API중 User32.dll안에 있는 MessageBox함수를 호출형태 입니다.
int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);  

     [DllImport("kernel32.dll")]  
     private static extern bool Beep(int freq, int dur);   

     [STAThread]  
     static void Main(string[] args)  
     {  
          MessageBox(0, "MessageBox Text", "DllImport Test", 2);  
          Beep(2600,1000);  
     }

위코드는 외부의 비관리(Unmanaged)코드에 있는 DLL을 특정 프로세스 메모리에 로딩하여 해당 메소드를 호출하여 사용한 예입니다.

※ extern 키워드 : 어떤 메서드가 현재 프로그램 외부에 있음을 나타내는 키워드

'GET > Attribute' 카테고리의 다른 글

참고 사이트.  (0) 2009.09.24
간단 예제.  (0) 2009.09.24
* Conditional 어트리뷰트 사용  (0) 2009.09.24
Attrubute(어트리뷰트)  (0) 2009.09.24
Attribute Oriented Programming  (0) 2009.09.24
posted by 방랑군 2009. 9. 24. 14:52

 특성. - 코드에 대한 설명문매타데이타)

1. 멤버 앞에 [특성(특성값)] 식으로 붙여서 사용
2. 분야(Web, XML..) 에 따라서 많은 내장 특성이 있다.
3. 사용자 정의 특성을 만들고자 할 때에는 System.Attribute 를 상속 받아 설계
4. 특성을 통해서 런타임 시에 추가적인 기능을 부여가능.
5. 자동차로 따지면 자동차 악세사리



01 | 개요(Overview of Attributes)
    어트리뷰트는 클래스 안에 메타정보를 포함 시킬 수 있는 새로운 기술입니다. 어트리뷰트는 선언적 컴파일을 지원하기 때문에 코딩에 많은 이점을 주고 있으며 특히 컴포넌트를 만들 때 유용하게 쓸 수 있습니다.

실제, 어트리뷰트는 클래스 멤버변수로 관리하기에는 적절하지 않고 주로 코드 외부에서 어떤 자료형에 대한 서술이 필요할 때 많이 사용하는 편입니다.

Attributes 소개
    어트리뷰트는 최근 자바 이노테이션(Annotation)의 등장으로 어트리뷰트 오리엔티드 프로그래밍(attribute oriented programming)에 대한 관심이 많아 지고 있습니다. 하지만 어트리뷰트 오리엔티드 프로그래밍은 마이크로소프트(이하 MS)진영에서 COM, COM+개발에서 부분적으로 이미 사용하고 있고 닷넷 프레임워크 경우 어트리뷰티드 프로그래밍이라는 이름으로 지원하고 있습니다.

어트리뷰트 오렌티드 프로그래밍이란 프로그램 레벨에서의 마킹 기법입니다.
이를 사용하면 프로그램을 개발할 때 프로그램과 관련된 메타데이터를 정보를 저장하고 이 정보를 이용하여 디자인&컴파일 타임 로딩 또는 런타임 시에 원하는 동작을 수행 하도록 할 수 있습니다.


예를 들면 트랜잭션(Transaction)이라는 어트리뷰트를 선언한 클래스는 클래스의 메소드를 실행할 때 트랜잭션 컨텍스트 내에서 수행 되도록 한다. 이러한 기법은 코어 비즈니스 로직과 트랜잭션과 로깅과 같은 횡단 관심사(Cross-cutting concerns)를 분리한다는 점에서 AOP(Aspect Oriented Programming) 기법과 유사합니다.

* 어트리뷰티드 프로그래밍 패러다임의 시작
    어트리뷰티드 프로그래밍 기법은 COM 기반 프로그래밍에서의 인터페이스 정의 언어(Interface Definition Language)에서 사용되기 시작했다. 라이브러리와 클래스의 uuid나 helpstring같은 프로그램에 대한 메타데이터 값들을 라이브러리나 클래스의 정의에 다음과 같이 선언해 컴파일 시에 참조할 수 있도록 지원 합니다.

[uuid(74731E6F-A0E8-47FB-833C-8D6C75E85981),
helpstring("MessengerAx Control"), control]
coclass MessengerAx


이러한 기법은 COM+ 기반을 발전하면서 애플리케이션의 트랙젹선 설정과 풀리, 보안 설정 등의 메타데이터 정보를 구성요소 서비스와 같은 별도의 저장소를 이용해 등록한 후 이정보를 런타임시 참조를 해야 동작이 가능합니다.

하지만 이러한 기능을 닷넷 에서는 이보다 한 단계 더 발전된 형태로 어트리뷰트를 별도의 저장소가 아닌 프로그램 내에 직접 저장할 수 있고 동작이 가능합니다.

어트리뷰트는 클래스 뿐만 아니라 데이터 구조, 열거자 그리고 어셈블리와 같은 프로그래밍적 요소들의 실행시 행동에 대한 정보를 기술 할수 있습니다. 어트리뷰트를 아티클을 보시는 여러분들은 코드에 대해서 어떻게 지정되고 사용되는지에 대한 주석으로 생각 할수도 있습니다. 하지만 일반 주석의 의해 전달되는 정보들은 일정한 틀이 없고 그것을 정형화하기 힘듭니다. 또한 그 정보들에 대해 런타임상의 접근하기가 어렵습니다.

어트리뷰트는 메타데이터지만 일종의 클래스입니다.
어트리뷰트를 정의해서 사용하게 되면 어떠한 클래스에 대해 설명할 때 이 어트리뷰트를 사용해서 설명할수 있고 주석처럼 직접 소스를 보아야 알수 있는 정보들을 어셈블리 안에 직접 넣거나 그 정보을 보는 방법도 코드레벨에서 가능합니다. 즉, 어트리뷰트는 작성한 클래스와 어떤 정보들(ex>이 클래스는 누가 디자인했고 라이센스는 누구한테 있으며 버전은 몇버전이다) 을 연결시켜주는 기술을 지원합니다.

* 어트리뷰트 시용
어트리뷰트를 사용할 수 있는 요소는 다음과 같습니다.
어트리뷰트를 사용할 수 있는 요소들
 어셈블리, 모듈, 클래스, 구조체, 열거형, 변수, 생성자, 메소드, 프로퍼티, 필드, 이벤트, 인터페이스, 파라미터,
 반환값, 델리게이트

* 어트리뷰트 문장 형식
attribute(positional_parameters, name_parameter = value, ...)]

'[ ]' 안에 무슨 메소드와 같은 것이 쓰여져 있습니다. 그리고 그 메소드 안에 파라미터들이 있습니다.

여기서 파리미터는 두가지를 의미합니다. 하나는 위치지정 파라미터(positional_parameter)로 꼭 필요한 정보들을 기술할때 쓰며 위치 지정 파라미터는 반드시 넣어줘야하는 정보들입니다. 두번째로는 명명 파라미터(name_parameter)는 꼭 필요하지 않지만 사용자에 따라서 넣을 수도 있고 그렇지 않을수도 있습니다. 어트리뷰트 안에 추가적인 정보를 집어 넣을때 사용됩니다.

* 어트리뷰트 사용 예
[AdditionalInfo("2009-05-20")]
public class Test
{
   //TODO :  내용
}

여기서 AdditionalInfo는 어트리뷰트 이며 "2009-05-20"는 위치지정 파리미터가 됩니다. 개발하고자하는 코드바로위에 어트리뷰트를 써주면 됩니다.


'GET > Attribute' 카테고리의 다른 글

참고 사이트.  (0) 2009.09.24
간단 예제.  (0) 2009.09.24
* Conditional 어트리뷰트 사용  (0) 2009.09.24
* DllImport 어트리뷰트  (0) 2009.09.24
Attribute Oriented Programming  (0) 2009.09.24
posted by 방랑군 2009. 9. 24. 14:49

'GET > Attribute' 카테고리의 다른 글

참고 사이트.  (0) 2009.09.24
간단 예제.  (0) 2009.09.24
* Conditional 어트리뷰트 사용  (0) 2009.09.24
* DllImport 어트리뷰트  (0) 2009.09.24
Attrubute(어트리뷰트)  (0) 2009.09.24
posted by 방랑군 2009. 9. 24. 13:47


App.config

<?xml version="1.0" encoding="utf-8" ?>

<configuration>


  <configSections>

    <section name="unity" type="Console_Config_User.UserInfo,Console_Config_User" />

  </configSections>


  <unity>

    <NAME>황승재</NAME>

    <ADDRESS>염창동</ADDRESS>

    <HP>016-647-0678</HP>

  </unity>

</configuration>


unity.xml - 객체만들 부분만 뽑아서 XML 만든다.

<?xml version="1.0" encoding="utf-8" ?>

<unity>

  <NAME>황승재</NAME>

  <ADDRESS AD1="서울시" AD2="염창동" AD3="동아3차아파트" AD4="307동 1101호" />

  <HP>016-647-0678</HP>

</unity> 



XSD.EXE 로 XSD 파일 만들고 CLASS 객체 파일 만든다.

>xsd.exe unity.xml


>xsd.exe unity.xsd /c


unity.cs

//------------------------------------------------------------------------------

// <auto-generated>

//     This code was generated by a tool.

//     Runtime Version:2.0.50727.3082

//

//     Changes to this file may cause incorrect behavior and will be lost if

//     the code is regenerated.

// </auto-generated>

//------------------------------------------------------------------------------


using System.Xml.Serialization;


// 

// This source code was auto-generated by xsd, Version=2.0.50727.1432.

// 

namespace Console_Config_User

{


    /// <remarks/>

    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.1432")]

    [System.SerializableAttribute()]

    [System.Diagnostics.DebuggerStepThroughAttribute()]

    [System.ComponentModel.DesignerCategoryAttribute("code")]

    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]

    [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]

    public partial class unity

    {


        private string nAMEField;


        private string hpField;


        private unityADDRESS[] aDDRESSField;


        /// <remarks/>

        [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]

        public string NAME

        {

            get

            {

                return this.nAMEField;

            }

            set

            {

                this.nAMEField = value;

            }

        }


        /// <remarks/>

        [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]

        public string HP

        {

            get

            {

                return this.hpField;

            }

            set

            {

                this.hpField = value;

            }

        }


        /// <remarks/>

        [System.Xml.Serialization.XmlElementAttribute("ADDRESS", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]

        public unityADDRESS[] ADDRESS

        {

            get

            {

                return this.aDDRESSField;

            }

            set

            {

                this.aDDRESSField = value;

            }

        }

    }


    /// <remarks/>

    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.1432")]

    [System.SerializableAttribute()]

    [System.Diagnostics.DebuggerStepThroughAttribute()]

    [System.ComponentModel.DesignerCategoryAttribute("code")]

    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]

    public partial class unityADDRESS

    {


        private string aD1Field;


        private string aD2Field;


        private string aD3Field;


        private string aD4Field;


        /// <remarks/>

        [System.Xml.Serialization.XmlAttributeAttribute()]

        public string AD1

        {

            get

            {

                return this.aD1Field;

            }

            set

            {

                this.aD1Field = value;

            }

        }


        /// <remarks/>

        [System.Xml.Serialization.XmlAttributeAttribute()]

        public string AD2

        {

            get

            {

                return this.aD2Field;

            }

            set

            {

                this.aD2Field = value;

            }

        }


        /// <remarks/>

        [System.Xml.Serialization.XmlAttributeAttribute()]

        public string AD3

        {

            get

            {

                return this.aD3Field;

            }

            set

            {

                this.aD3Field = value;

            }

        }


        /// <remarks/>

        [System.Xml.Serialization.XmlAttributeAttribute()]

        public string AD4

        {

            get

            {

                return this.aD4Field;

            }

            set

            {

                this.aD4Field = value;

            }

        }

    }


    /// <remarks/>

    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.1432")]

    [System.SerializableAttribute()]

    [System.Diagnostics.DebuggerStepThroughAttribute()]

    [System.ComponentModel.DesignerCategoryAttribute("code")]

    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]

    [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]

    public partial class NewDataSet

    {


        private unity[] itemsField;


        /// <remarks/>

        [System.Xml.Serialization.XmlElementAttribute("unity")]

        public unity[] Items

        {

            get

            {

                return this.itemsField;

            }

            set

            {

                this.itemsField = value;

            }

        }

    }

}



UserInfo.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;


using System.Configuration;

using System.Xml;


namespace Console_Config_User

{

    class UserInfo : System.Configuration.IConfigurationSectionHandler

    {


#region IConfigurationSectionHandler 멤버


public object Create(object parent, object configContext, System.Xml.XmlNode section)

{

    //throw new NotImplementedException();

    XmlDocument doc = new XmlDocument();

    doc.LoadXml(section.OuterXml);

    Console_Config_User.unity objClass = new unity();

    objClass = (unity)xxml.ToInstance(doc, typeof(unity));


    return objClass;

}


#endregion

    }

}



Program.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;


using System.Configuration;


namespace Console_Config_User

{

    class Program

    {

        static void Main(string[] args)

        {


            //object config = ConfigurationManager.GetSection("unity");


            unity container = new unity();

            container = (unity)ConfigurationManager.GetSection("unity");

            

        }

    }

}




결과.





posted by 방랑군 2009. 9. 24. 13:05


개념은 "타겟 객체에 대한 호출을 중간에서 인터셉트할 수 있는 방법"이라는 것이다. 개발 프레임워크 입장에서 생각해본다면 얼마나 근사한 구조인가. 타겟 객체( 개발자가 개발)에 대한 모든 호출( 개발자가 만든 코드에서의 호출)을 개발 프레임워크에서 캐취할 수 있다는 것은 많은 장점을 가지고 있다.
posted by 방랑군 2009. 9. 24. 11:27

첨부파일 :

XMLFile2.xml

<?xml version="1.0" encoding="UTF-8" ?>

<Root>

  <Record>

    <Field1>Field1_0</Field1>

    <Field2>Field2_0</Field2>

  </Record>

  <Record2 Field2="Field2_0" Field3="Field3_1" />

  <Field1>Field1_0</Field1>

  <Field2>Field2_0</Field2>

</Root>




>xsd.exe XMLFile2.xml
XMLFile2.xml

<?xml version="1.0" encoding="utf-8"?>

<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">

  <xs:element name="Root">

    <xs:complexType>

      <xs:sequence>

        <xs:element name="Field1" type="xs:string" minOccurs="0" />

        <xs:element name="Field2" type="xs:string" minOccurs="0" />

        <xs:element name="Record" minOccurs="0" maxOccurs="unbounded">

          <xs:complexType>

            <xs:sequence>

              <xs:element name="Field1" type="xs:string" minOccurs="0" />

              <xs:element name="Field2" type="xs:string" minOccurs="0" />

            </xs:sequence>

          </xs:complexType>

        </xs:element>

        <xs:element name="Record2" minOccurs="0" maxOccurs="unbounded">

          <xs:complexType>

            <xs:attribute name="Field2" type="xs:string" />

            <xs:attribute name="Field3" type="xs:string" />

          </xs:complexType>

        </xs:element>

      </xs:sequence>

    </xs:complexType>

  </xs:element>

  <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">

    <xs:complexType>

      <xs:choice minOccurs="0" maxOccurs="unbounded">

        <xs:element ref="Root" />

      </xs:choice>

    </xs:complexType>

  </xs:element>

</xs:schema>


>xsd.exe XMLFile2.xsd /c
XMLFile2.cs

//------------------------------------------------------------------------------

// <auto-generated>

//     This code was generated by a tool.

//     Runtime Version:2.0.50727.3082

//

//     Changes to this file may cause incorrect behavior and will be lost if

//     the code is regenerated.

// </auto-generated>

//------------------------------------------------------------------------------


using System.Xml.Serialization;


// 

// This source code was auto-generated by xsd, Version=2.0.50727.1432.

// 



/// <remarks/>

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.1432")]

[System.SerializableAttribute()]

[System.Diagnostics.DebuggerStepThroughAttribute()]

[System.ComponentModel.DesignerCategoryAttribute("code")]

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]

[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]

public partial class Root {

    

    private string field1Field;

    

    private string field2Field;

    

    private RootRecord[] recordField;

    

    private RootRecord2[] record2Field;

    

    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]

    public string Field1 {

        get {

            return this.field1Field;

        }

        set {

            this.field1Field = value;

        }

    }

    

    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]

    public string Field2 {

        get {

            return this.field2Field;

        }

        set {

            this.field2Field = value;

        }

    }

    

    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute("Record", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]

    public RootRecord[] Record {

        get {

            return this.recordField;

        }

        set {

            this.recordField = value;

        }

    }

    

    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute("Record2", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]

    public RootRecord2[] Record2 {

        get {

            return this.record2Field;

        }

        set {

            this.record2Field = value;

        }

    }

}


/// <remarks/>

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.1432")]

[System.SerializableAttribute()]

[System.Diagnostics.DebuggerStepThroughAttribute()]

[System.ComponentModel.DesignerCategoryAttribute("code")]

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]

public partial class RootRecord {

    

    private string field1Field;

    

    private string field2Field;

    

    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]

    public string Field1 {

        get {

            return this.field1Field;

        }

        set {

            this.field1Field = value;

        }

    }

    

    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]

    public string Field2 {

        get {

            return this.field2Field;

        }

        set {

            this.field2Field = value;

        }

    }

}


/// <remarks/>

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.1432")]

[System.SerializableAttribute()]

[System.Diagnostics.DebuggerStepThroughAttribute()]

[System.ComponentModel.DesignerCategoryAttribute("code")]

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]

public partial class RootRecord2 {

    

    private string field2Field;

    

    private string field3Field;

    

    /// <remarks/>

    [System.Xml.Serialization.XmlAttributeAttribute()]

    public string Field2 {

        get {

            return this.field2Field;

        }

        set {

            this.field2Field = value;

        }

    }

    

    /// <remarks/>

    [System.Xml.Serialization.XmlAttributeAttribute()]

    public string Field3 {

        get {

            return this.field3Field;

        }

        set {

            this.field3Field = value;

        }

    }

}


/// <remarks/>

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.1432")]

[System.SerializableAttribute()]

[System.Diagnostics.DebuggerStepThroughAttribute()]

[System.ComponentModel.DesignerCategoryAttribute("code")]

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]

[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]

public partial class NewDataSet {

    

    private Root[] itemsField;

    

    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute("Root")]

    public Root[] Items {

        get {

            return this.itemsField;

        }

        set {

            this.itemsField = value;

        }

    }

}




쓸데없는 Attribute 제거 후 객체 모양

using System.IO;

using System.Xml;

using System.Xml.Serialization;


using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace Console_XML.In4

{


    /// <remarks/>

    [System.Serializable]

    //[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]

    public class Root

    { 


        /// <remarks/>

        

        public RootRecord Record

        {

            get { return _Record; }

            set { _Record = value; }

        }

        private RootRecord _Record = new RootRecord();



        /// <remarks/>

        

        public RootRecord2 Record2

        {

            get { return _Record2; }

            set { _Record2 = value; }

        }

        private RootRecord2 _Record2 = new RootRecord2();



        /// <remarks/>

        

        public string Field1

        {

            get { return _Field1; }

            set { _Field1 = value; }

        }

        private string _Field1 = "";



        /// <remarks/>

        

        public string Field2

        {

            get { return _Field2; }

            set { _Field2 = value; }

        }

        private string _Field2 = "";


    }


    /// <remarks/>

    [System.Serializable]    

    public class RootRecord

    {


        /// <remarks/>

        

        public string Field1

        {

            get { return _Field1; }

            set { _Field1 = value; }

        }

        private string _Field1 = "";



        /// <remarks/>

        

        public string Field2

        {

            get { return _Field2; }

            set { _Field2 = value; }

        }

        private string _Field2 = "";


    }


    /// <remarks/>

    [System.Serializable]    

    public class RootRecord2

    {


        /// <remarks/>

        [System.Xml.Serialization.XmlAttributeAttribute()]

        public string Field2

        {

            get { return _Field2; }

            set { _Field2 = value; }

        }

        private string _Field2 = "";



        /// <remarks/>

        [System.Xml.Serialization.XmlAttributeAttribute()]

        public string Field3

        {

            get { return _Field3; }

            set { _Field3 = value; }

        }

        private string _Field3 = "";


    }


}



XML <-> CLASS 할 함수

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



using System.Xml;

using System.IO;

using System.Xml.Serialization;



namespace Console_XML

{

    class xxml

    {


        /// <summary>

        /// XML -> yyyyMMdd\FILE

        /// </summary>

        /// <param name="doc"></param>

        /// <param name="path"></param>

        public static void XMLDoctoFile(XmlDocument doc, string path)

        {

            string _Date = DateTime.Now.ToString("yyyyMMdd", System.Globalization.DateTimeFormatInfo.InvariantInfo);

            string[] _path = path.Split(new char[] { '\\' });

            string _fullpath = "";

            for (int i = 0; i < _path.Length - 1; i++)

            {

                _fullpath += _path[i] + "\\";


            }

            // 디렉토리 검색

            if (!System.IO.Directory.Exists(_fullpath + "\\" + _Date))

            {

                Directory.CreateDirectory(_fullpath + "\\" + _Date);

            }


            path = _fullpath + "\\" + _Date + "\\" + _path[_path.Length - 1];


            XmlTextWriter writer = new XmlTextWriter(path, new UTF8Encoding());

            try

            {

                writer.Formatting = Formatting.Indented;

                writer.Indentation = 4;

                doc.WriteContentTo(writer);

            }

            finally

            {

                writer.Close();

            }

        }



        /// <summary>

        /// XML -> yyyyMMdd\FILE

        /// </summary>

        /// <param name="doc"></param>

        /// <param name="path"></param>

        public static void XMLDoctoFileEx(XmlDocument doc, string path)

        {

            string _Date = DateTime.Now.ToString("yyyyMMdd", System.Globalization.DateTimeFormatInfo.InvariantInfo);

            string _Hour = DateTime.Now.ToString("HH", System.Globalization.DateTimeFormatInfo.InvariantInfo);

            string[] _path = path.Split(new char[] { '\\' });

            string _dirPath = "";

            string _fullpath = "";

            for (int i = 0; i < _path.Length - 1; i++)

            {

                _fullpath += _path[i] + "\\";


            }


            _dirPath = _fullpath + "\\" + _Date + "\\" + _Hour;

            // 디렉토리 검색

            if (!System.IO.Directory.Exists(_dirPath))

            {

                Directory.CreateDirectory(_dirPath);

            }


            path = _dirPath + "\\" + _path[_path.Length - 1];


            XmlTextWriter writer = new XmlTextWriter(path, new UTF8Encoding());

            try

            {

                writer.Formatting = Formatting.Indented;

                writer.Indentation = 4;

                doc.WriteContentTo(writer);

            }

            catch (Exception err)

            {

                System.Diagnostics.EventLog.WriteEntry("VTFramework", "[vS_XML:XMLDoctoFileEx]:" + err.Message, System.Diagnostics.EventLogEntryType.Error);

            }

            finally

            {

                writer.Close();

            }

        }


        /// <summary>

        /// 객체를 xmlDocument로 전환 하는 함수.

        /// </summary>

        /// <param name="obj"></param>

        /// <returns></returns>

        public static XmlDocument ToMessage(object obj)

        {

            try

            {

                XmlSerializer serializer = new XmlSerializer(obj.GetType());

                MemoryStream stream = new MemoryStream();

                StreamReader reader = new StreamReader(stream);

                serializer.Serialize(stream, obj);

                stream.Position = 0;

                XmlDocument doc = new XmlDocument();

                doc.LoadXml(reader.ReadToEnd());

                try

                {

                    return doc;

                }

                finally

                {

                    reader.Close();

                    stream.Close();

                }

            }

            catch (Exception exc)

            {

                System.Diagnostics.EventLog.WriteEntry("VTFramework", "[vS_XML:ToMessage]:" + exc.Message, System.Diagnostics.EventLogEntryType.Error);

                throw new Exception("객체 생성중 오류가 발생했읍니다![ToInstance", exc);

            }

        }


        /// <summary>

        /// xmlDocument를 객체로 변환하는 함수

        ///  XML -> CLASS

        /// ex)

        ///   1. 변환할 클래스의 필드가 적어도 많아도 적용이 됨

        ///   2. 다른 필드가 존재해도 적용이 됨

        /// </summary>

        /// <param name="doc"></param>

        /// <param name="type"></param>

        /// <returns></returns>

        public static object ToInstance(XmlDocument doc, System.Type type)

        {

            try

            {

                XmlSerializer serializer = new XmlSerializer(type);

                MemoryStream writeStream = new MemoryStream();

                MemoryStream readStream = new MemoryStream();


                XmlTextWriter writer = new XmlTextWriter(writeStream, null);

                doc.WriteContentTo(writer);

                writer.Flush();


                writeStream.Position = 0;


                writeStream.WriteTo(readStream);

                writer.Close();

                writeStream.Close();


                readStream.Position = 0;

                XmlTextReader reader = new XmlTextReader(readStream);

                try

                {

                    return serializer.Deserialize(reader);

                }

                finally

                {

                    reader.Close();

                    readStream.Close();

                }

            }

            catch (Exception exc)

            {

                throw new Exception("객체 생성중 오류가 발생했읍니다![ToInstance", exc);

            }

        }

    }

}




XML -> CLASS 객체로 변환 소스

doc.Load(@"XMLFile2.xml");


Console_XML.In4.Root objInstance3 = (Console_XML.In4.Root)xxml.ToInstance(doc, typeof(Console_XML.In4.Root));


posted by 방랑군 2009. 9. 23. 15:23

        static void Main(string[] args)

        {



            StringBuilder strXML = new StringBuilder(); 

            strXML.AppendLine(@"<?xml version=""1.0"" encoding=""utf-8"" ?>");

            strXML.AppendLine(@"<unity>");

            strXML.AppendLine(@"<NAME>황승재</NAME>");

            strXML.AppendLine(@"<ADDRESS AD1=""서울시"" AD2=""염창동"" AD3=""동아3차아파트"" AD4=""307동 1101호"" />");

            strXML.AppendLine(@"<HP>016-647-0678</HP>");

            strXML.AppendLine(@"</unity>");

            strXML.AppendLine("");



            XmlDocument doc = new XmlDocument();

            doc.LoadXml(strXML.ToString());


            ///

            ///

            string strNode1 = doc.SelectSingleNode("unity/NAME").InnerText;

            string strNode2 = doc.SelectSingleNode("unity/ADDRESS").Attributes["AD1"].Value;



            doc = null;

        }




posted by 방랑군 2009. 9. 23. 14:48


  <unity>

    <NAME>황승재</NAME>

    <ADDRESS AD1="서울시" AD2="염창동" AD3="동아3차아파트" AD4="307동 1101호" />

    <HP>016-647-0678</HP>

  </unity>


ADDRESS 의 Attribute 값 가져오는 법


section.SelectSingleNode("ADDRESS").Attributes["AD1"].Value

"서울시"


/// 더미..

section.SelectSingleNode("ADDRESS").OuterXml

"<ADDRESS AD1=\"서울시\" AD2=\"염창동\" AD3=\"동아3차아파트\" AD4=\"307동 1101호\" />"

section.SelectSingleNode("ADDRESS").Attributes["AD1"].OuterXml

"AD1=\"서울시\""




ADDRESS 의 Element 값 가져오는 법

section.SelectSingleNode("NAME").InnerText; 

"황승재"



IConfigurationSectionHandler  에서 값 할당

#region IConfigurationSectionHandler 멤버


public object Create(object parent, object configContext, System.Xml.XmlNode section)

{

    //throw new NotImplementedException();


    UserInfo obj = new UserInfo();


    

    obj._NAME    = section.SelectSingleNode("NAME").InnerText; // section 이용하여 config 값 넣는다.  

    obj._ADDRESS = doc.SelectSingleNode("unity/ADDRESS").Attributes["AD1"].Value;

    obj._HP      = section.SelectSingleNode("HP").InnerText; // section 이용하여 config 값 넣는다.

    return obj;

}


#endregion


posted by 방랑군 2009. 9. 23. 14:24



Understanding Section Handlers - App.config File

참조 : http://www.codeproject.com/KB/aspnet/ConfigSections.aspx


예제 Config

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

//1 SECTIOIN 구성등

<configSections>

<sectionGroup name="settings">

<section name="dbSettings" type="System.Configuration.NameValueSectionHandler"/>

</sectionGroup>

<sectionGroup name="inputScreen">

<section name="education" type="System.Configuration.DictionarySectionHandler"/>

<section name="sex" type="System.Configuration.SingleTagSectionHandler"/>

</sectionGroup>

<sectionGroup name="companyInfo">

<section name="companyAddress" type="ConfigSections.MyConfigHandler,ConfigSections"/>

</sectionGroup>

</configSections>


<settings>

<dbSettings>

<add key="connectionString" value="Data Source=localhost;Initial Catalog=Northwind;"/>

<add key="imagesPath" value="c:\MyApp\Resources\Images\"/>

</dbSettings>

</settings>


<inputScreen>

<education>

<add key="1" value="High School"/>

<add key="2" value="Bachelors"/>

<add key="3" value="Masters"/>

<add key="4" value="Doctorate"/>

</education>

<sex Male="1" Female="2"/>

</inputScreen>


<companyInfo> 

<companyAddress> 

<companyName>Axxonet Solutions India Pvt Ltd</companyName>

<doorNo>1301</doorNo>

<street>13th Cross, Indira Nagar, 2nd Stage</street>

<city>Bangalore</city>

<postalCode>560038</postalCode>

<country>India</country>

</companyAddress>

</companyInfo>


<!--

Read appsettings from an external file.

-->

<appSettings file="appSettings.xml"/>

<appSettings>

<add key="author" value="Palanisamy Veerasingam"/>

<add key="article" value="Configuration Sections"/>

</appSettings>

</configuration>


.NET 1.1 호출 밥법

NameValueCollection nvc=(NameValueCollection)ConfigurationSettings.GetConfig("settings/dbSettings");

            MessageBox.Show("Connection String is " + nvc[0].ToString() );



Hashtable objHash=(Hashtable) ConfigurationSettings.GetConfig("inputScreen/education");

MessageBox.Show("Education list count is " + objHash.Count);


Hashtable objHash=(Hashtable) ConfigurationSettings.GetConfig("inputScreen/sex");

MessageBox.Show("Value of male is " + objHash["Male"].ToString() );

CCompanyAddr obj=(CCompanyAddr)ConfigurationSettings.GetConfig("companyInfo/companyAddress"); 

string strMsg;

strMsg = "Company Address is:\n" +

 "\n" + obj.CompanyName +

 "\n" + obj.DoorNo + ", " + obj.Street +

 "\n" + obj.City + 

     "\n" + obj.Country;

MessageBox.Show(strMsg);



string strAuthor=ConfigurationSettings.AppSettings["author"];

MessageBox.Show("This sample is coded by " + strAuthor);



.NET 2.0... 






posted by 방랑군 2009. 9. 23. 14:19

Using Alternative Configuration Sources

You can also use any XML configuration file or other source of configuration information if required. For example, you can load configuration information into containers from a specific named configuration file by using the .NET Framework System.Configuration.Configuration class to retrieve the information from any XML formatted file. The following code shows how you can read configuration information from a file named MyConfig.config.


클래스 ExeConfigurationFileMap 

namespace System.Configuration

{

    // 요약:

    //     Exe.config 파일의 구성 파일 매핑을 정의합니다. 이 클래스는 상속될 수 없습니다.

    public sealed class ExeConfigurationFileMap : ConfigurationFileMap


참조 : Unity Application Block 1.2 - October 2008 Configuring Containers at Design Time

ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = "MyConfig.config";
System.Configuration.Configuration config 
  = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None); 
UnityConfigurationSection section
  = (UnityConfigurationSection)config.GetSection("unity");
IUnityContainer container = new UnityContainer();
section.Containers["myContainer"].Configure(container);


- Unity Application Block 에서 사용 소스..

 private SysConfiguration OpenConfigFile(string baseName)

        {

            ExeConfigurationFileMap map = new ExeConfigurationFileMap();

            map.ExeConfigFilename = baseName + ".config";

            return ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);

        }





posted by 방랑군 2009. 9. 23. 14:12


[Format of the Unity Configuration File]

  <configSections>

    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />

  </configSections>

- UnityConfigurationSection 클래스에 맞는 Config 구성

UnityConfigurationSection section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;

UnityConfigurationSection 에 매핑해서 활용

    public class UnityConfigurationSection : ConfigurationSection

    {

.

.

ConfigurationSection 이걸 상속함으로써 :IConfigurationSectionHandler 역활 대신한다.
ConfigurationSection 안에 UNITY 만의 구성된 포맷이 정의 되어 있는거 같음...



posted by 방랑군 2009. 9. 23. 13:45


An error occurred creating the configuration section handler for xx 에러 관련

예)
An error occurred creating the configuration section handler for unity: Could not load file or assembly 'Microsoft.Practices.Unity.Configuration' or one of its dependencies. The system cannot find the file specified. (F:\#Document#\[[SPRING.NET]]\[TEMPLETE]\Console_Plural_Genenic\Console_Config\bin\Debug\Console_Config.vshost.exe.Config line 5)

--> 어셈블 등록된 DLL을 못찾아 로딩이 안되어 생긴 문제.
   : 로컬복사를 TRUE로 해서 컴파일 위치에서 하면 된다.
     그리고, FALSE 하면 어셈블 등록된 DLL로 연결된다.


1. 위 예 처럼 Config 의 type 에 선언된 클래스가 로딩이 안된 경우....
   파일 위치를 로컬복사 하던지 어셈블 매핑을 확인한다(어떻게?? ㅋㅋ).


2. 위 1번 빼고 에러메세지 자세히 보면 해결돤다..
    1번도 메세지 보고 가능한데 생각의 전환이 안되 찾지 못한다.. ㅋㅋㅋ
posted by 방랑군 2009. 9. 23. 13:43

 로컬파일에 존재하는 건 제대로 casting 되었는데,
강한 어셈블 DLL 로딩하면 에러가 안나고 "System.Configuration.DefaultSection" 로 CASTING 된다. 
  - 원래 안되었는데 로컬파일 된다음 하니 물려서 된다. 니미(--;)~~.. 근데 잘못 CASTING 된다...
    원래 System.Configuration.DefaultSection 에 매핑되는건지 아님 에러가 나는지 
"Microsoft.Practices.Unity.Configuration.UnityConfigurationSection" 에 CASTING
되는지 확인해보야 하나 그럼 엄청난 삽질과 재설치 테스트를 해야한다.. 그래서, 패스~


  <configSections>

//1) 실행파일 로컬에 존재 해야 함(본인 실행파일이나 DLL)

    <section name="unity2" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />

  </configSections>


//2) 어셈블리에 등록된 DLL 를 호출하는 경우

  <configSections>

    <section name="unity"

              type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,

                 Microsoft.Practices.Unity.Configuration, =1.3.0.0,

                 Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

  </configSections>

.

.

.

  

</configuration>



            Configuration currentConfig =                ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

            object config = currentConfig.GetSection("unity2");


            Configuration currentConfig =                ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

            object config = currentConfig.GetSection("unity");



'GET > Configuration' 카테고리의 다른 글

사용자가 임의로 만든 any XML configuration file 제어  (1) 2009.09.23
Unity Application Block 에서의 Configuration  (1) 2009.09.23
Error 처리  (0) 2009.09.23
Sample - 1  (0) 2009.09.23
XML Config 제어하기.  (0) 2009.09.23
posted by 방랑군 2009. 9. 23. 13:07




App.config

<?xml version="1.0" encoding="utf-8" ?>

<configuration>


  <configSections>

    <section name="unity" type="Console_Config_User.UserInfo,Console_Config_User" />

  </configSections>


  <unity>

    <NAME>황승재</NAME>

    <ADDRESS>염창동</ADDRESS>

    <HP>016-647-0678</HP>

  </unity>

</configuration>


Console_Config_User.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;


using System.Configuration;


namespace Console_Config_User

{

    class UserInfo : System.Configuration.IConfigurationSectionHandler

    {


        public string _NAME;

        public string _ADDRESS;

        public string _HP;


        public UserInfo()

        {

            _NAME =

            _ADDRESS =

            _HP = "";

            

        }


        #region IConfigurationSectionHandler 멤버


        public object Create(object parent, object configContext, System.Xml.XmlNode section)

        {

            //throw new NotImplementedException();


            UserInfo obj = new UserInfo();


            ///

            /// section.SelectSingleNode("config").InnerText;

            ///

            obj._NAME    = section.SelectSingleNode("NAME").InnerText; // section 이용하여 config 값 넣는다.  

            obj._ADDRESS = section.SelectSingleNode("ADDRESS").InnerText; // section 이용하여 config 값 넣는다.

            obj._HP      = section.SelectSingleNode("HP").InnerText; // section 이용하여 config 값 넣는다.

            return obj;

        }


        #endregion

    }

}


- object parent, object configContext 이거 null 로 들어옴... 


Program.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;


using System.Configuration;


namespace Console_Config_User

{

    class Program

    {

        static void Main(string[] args)

        {


            //object config = ConfigurationManager.GetSection("unity");


            UserInfo container = new UserInfo();

            container = (UserInfo)ConfigurationManager.GetSection("unity");

            

        }

    }

}




posted by 방랑군 2009. 9. 23. 12:46

0. .NET 1.1 ConfigurationSettings.GetConfig("") 와 IConfigurationSectionHandler
    .NET 2.0 ConfigurationManager.GetSection("") 와 IConfigurationSectionHandler

1. App.config, Web.config. machine.config 등 정해진 Config 제어

2. 사용자가 임의로 만든 any XML configuration file 제어

3. Unity Application Block 에서의 Configuration

'GET > Configuration' 카테고리의 다른 글

사용자가 임의로 만든 any XML configuration file 제어  (1) 2009.09.23
Unity Application Block 에서의 Configuration  (1) 2009.09.23
Error 처리  (0) 2009.09.23
Config 의 type 과 DLL 과 연결 관련...  (0) 2009.09.23
Sample - 1  (0) 2009.09.23
posted by 방랑군 2009. 9. 15. 17:25



참조 : http://debop.egloos.com/2299315



C# 2.0 /3.0 New Features

작성자 : 리얼웹 개발본부 배성혁

 

들어가는 말

.NET Framework 버전과 C# Specification 버전이 꼭 일치하지는않지만유사하게 버전이 올라가고 있습니다. 2009년 현재 C# 4.0 Spec Preview가 공개되었고이를 .NET Framework 4.0, VS.NET 2010 부터 사용이 가능할 것 같습니다.

 

여러분은 처음 .NETFramework 또는 C#을 공부하면서문법, API 등을 공부하고쓰고 있지만 어떤 버전을 쓰고 있는지는 잘모르셨을 것이라 생각됩니다하지만 S/W 개발쪽에 경력이쌓이게 되면, version에 따라 변화되는 기능에 대해 어느정도 무의식 속에 파악하고수용하게 됩니다.

보통 어느정도 초보딱지를 뗀 개발자라면자신이 사용하는 툴이나 라이브러리를 가장 최신의 것으로 유지하려고 하는 경향이 있습니다. Early adapter라고 하지요… 하지만신제품 개발단계가 아닌 제품의 라이프사이클을 고려하게 되면꼭최신의 제품을 사용할 수 없을 때가 더 많아지기도 합니다. – backward compatibility가있는 제품이라면 영향이 작을 수는 있지만, Microsoft는 워낙 악명이 높습니다차라리 open source 진영에서 더 신경쓰고 있는 부분입니다.

 

제품 Spec을결정하던가버전관리를 주도하는 개발자는 사용하는 제품의 새로운 버전이 출시되었을 때 Upgrade를 해야 하는지를 고려해야 합니다아예 눈/귀를 닫아서는 안되고,Library 하나라도담당 제품의 많은 장점을 줄 수 있는 기능이 있는지?, 제품 개발 혹은 Customizing 시의 공수외부 인터페이스 변화 등을 고려해서신 버전 사용을 결정해야 합니다.

 

고려대상은 사용하는 제품마다 다르고독자 판단만으로 안되는 경우도 많습니다특히나 MS 제품은 무조건 신버전을 사용하도록(지들 제품 많이 팔리도록강요하는 경우가 많습니다. (여기에 놀아나지 말아야 하지만… 가만보면 제가 가장 많이 놀아나는 것도 같고…) – 고객 중에서도최신버전을 좋아하는 사람기존 버전을 고수하는 사람 등등 참 많습니다.

 

어쨌든 새로운 제품에 대해서는 항상 새로운 기능이 무엇인지뭐가 바뀌었는지기존 제품과의 호환성은 어떤지를 파악해야 합니다새로 도입할 제품도현재 버전이 어떤기능을 가졌는지발전 단계는 어떤지앞으로의 로드맵에는 어떤 기능이 있는지를 조사해야합니다.

 

그럼 이제부터 .NET Framework 2.0/3.0  이제 4.0이 공개될 건데왠 뒷북이라 할 수도 있지만 사실 개발자들이 C# 2.0 spec조차도 잘 사용하지 못하는 경우가 대부분이어서 – 의 새로운 기능에 대해 살펴보겠습니다.

 

먼저 C# 2.0 Spec부터 살펴보죠… 개인적으로 C# 2.0의 새로운 특성 중에 제일 반겼던 것은 Generic 을 지원한다는 것입니다물론 다른 좋은 기능들도 많지만굵은 글자로 되어 있는 부분이 제게는 도움이 많이 되었던 것들입니다.

대부분 실제 많이 사용하고 있는 기능들이므로설명이나 의미는 생략하겠습니다다만 Generic에 대해서는 다음 기회에 다시 설명하도록 하겠습니다.

 

표 1. C# 2.0 New Features

항목

설명

Generic

형식 매개 변수를 사용하여, run time 시에 cat, boxing 작업에 대한 위험없이 단일 class 작성 가능

Iteration

Yield return

Yield break;

Public void GetEnumerator()

{

    for(int i=0; i< _data.Count; i++)

        yield return _data[i];
}

Partial class

public partial class Employee { public void DoWork() { … } }

public partial class Employee { public void GoToLunch() { … } }

Nullable type

System.Nullable 구조체의 Instance

int? num = null;

int count = num ?? 0;

int count = num.GetValueOrDefault(0);

Anonymous method

Delegate void Del(int x);

Del d = delegate() {

    Console.WriteLine(“delete “ + x);

};

Static class

public static class Utils {

    public static void UtilityMethod() { … }

}

Property accessor

string FullName { get; protected set; }

Fixed size buffer

Public struct MyArray { public fixed char PathName[128]; }

Friendly assembly

[assembly:InternalsVisibleTo(“cs_friend_assemblies_2”)]

 

한가지 짚고 넘어가고 싶은 것은 Anonymous method 라는기능입니다이는 java 문법에서 제공되는 기능을 차용한것으로 보이는데앞으로 설명할 C# 3.0 spec에서이를 토대로 많은 기능들을 구현할 수 있음을 알 수 있습니다.

 

다음으로는 C# 2.0 (.NET Framework 2.0 이 더옳은 표현이지만, C#이 대표 Language이므로에서 새롭게 제공하는 delegate 에 대해 알아 보겠습니다.

 

표 2. C# 2.0 중요 Delegate

Type

Definition

Action

public delegate void Action<T> ( T arg )

public delegate void Action<T1, T2> ( T1 arg1, T2 arg2  )

public delegate void Action<T1, T2, T3> ( T1 arg1, T2 arg2, T3 arg3 )

public delegate void Action<T1, T2, T3, T4> ( T1 arg1, T2 arg2, T3 arg3, T4 arg4 )

Func

public delegate TResult Func<T, TResult> ( T arg )

public delegate TResult Func<T1, T2, TResult> ( T1 arg1, T2 arg2 )

public delegate TResult Func<T1, T2, T3, TResult> ( T1 arg1, T2 arg2, T3 arg3 )

public delegate TResult Func<T1, T2, T3, T4, TResult> ( T1 arg1, T2 arg2, T3 arg3, T4 arg4 )

Predicate

public bool Predicate<T>( T obj )

 

 2.에 나온 Action,Func, Predicate라는 delegate는 일반적으로는 많이 사용하는 delegate를 미리 정의해 둔 것이라 볼 수 있습니다특징중에 Generic을 이용한 것인데, Generic을 이용하면, signature는 하나지만다양한 Type을 지원하는 단 한 개의 delegate만을 정의해서 사용할수 있는 장점이 있습니다.

Action voidfunction point (C Language 용어)라 할 수 있는데,  지정된 형식의 인자를 N를 받아 수행하고반환값이 없는 함수를 말합니다.

Func는 반환값이 있다는 차이가 있고, Predicate Func<T, bool>(T arg) 와같은 뜻입니다.

 

위의 delegate를 보시면 메소드 인자의 개수가 최대 4개인데더 많은 인자를 가지는 메소드는 개발자가 추가로 정의하여사용이 가능합니다.

 

사용 예는 다음과 같습니다.

 

Func<stringstring> convert = delegate(string s)

                          {

                                  return s.ToUpper();

                          };   // anonymous method

string name = "Dakota";

 

Console.WriteLine(convert(name));

 

ð  DAKOTA

 

convert라는 delegate를만들고이를 사용하는 방식을 설명했습니다. Anonymousmethod 를 사용하여실제 delegate를위한 메소드 원형의 class에서 정의하지 않고내부적으로이름없는” 메소드를 정의하여 사용할 수 있습니다.

 

더 자세한 내용은

ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.ko/fxref_mscorlib/html/da586d48-5345-2de1-63f2-d6208f298942.htm

ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.ko/fxref_system.core/html/a0ab867a-da51-dd82-2e1a-e87b93712102.htm

를 참고하세요.

 

C# 2.0의 새로운 특징은 이쯤에서 정리하고 C# 3.0의 새로운 기능에 대해서 알아봅시다.

우선 MSDN C# 3.0의새로운 기능에 대한 설명은 ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.ko/dv_csref/html/e5193336-6adb-471e-ab22-e3fc60e0fa52.htm에 자세히 나와 있으니 참고하세요특히 새로운 기능의 필요성다른 새로운 기능의 토대가 되는지 등등을 파악하 보시기 바랍니다.

참고로 C# 3.5의 경우에는 ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.ko/dv_fxintro/html/1b0d91e8-2d01-47a0-affc-966894de71f8.htm에 있습니다. – 3.5에서는 Language 차원에서크게 발전된 건 없습니다.

 

그럼 C# 3.0에서 새롭게 도입된 기능을 알아 봅시다.

 

표 3. C# 3.0 Language enhancements

항목

설명

Local variable type inference

지역변수와 함께 사용될 경우 var 키워드는 초기화 문의 오른쪽에 있는 식에서 변수 또는 배열 요소의 형식을 유추하도록 컴파일러에게 지시한다.

 

var i = 5;

var s = "Hello";

var a = new[] {1,2,3};

for(var x =1; x <10; x++)

{

        // some codes

}

var 키워드는 "Variant"를 의미하지 않으며 변수가 느슨한 형식이거나 런타임에 바인딩됨을 의미하는게 아닙니다.

Object initialize

생성자를 명시적으로 호출하지 않고 개체 초기화를 수행할 수 있게 한다.

var cat = new Cat {Age = 10, Name = "Sylverster"};

 

Object intializer에 익명 형식 허용 단 nullable 형식은 불가

var o = new {Title = "Book In Action", Publisher = "Manning"};

 

Collection initialize

List<int> digits = new List<int> { 01234567 };

List<int> digits2 = new List<int> { 0+112 % 3, MakeInt() };

List<Cat> cats = new List<Cat> {

                       new Cat { Age=10, Name=“Sylverster” },

                       new Cat { Age=4, Name=“Peaches” },

                       null

               };

 

Anonymous types

익명 형식은 형식을 먼저 명시적으로 정의할 필요 없이 읽기 전용 속성 집합을 단일 개체로 캡슐화하는 편리한 방법을 제공합니다형식 이름은 컴파일러에 의해 생성되고 소스 코드 수준에서 사용할 수 없습니다속성의 형식은 컴파일러에 의해 유추됩니다다음 예제에서는 Amount 및 Message라는 두 개의 속성을 사용하여 초기화되는 익명 형식을 보여 줍니다.

 

var o = new {Title = "Book In Action", Publisher = "Manning"};

Auto-implemented properties

속성중에 추가 논리가 필요없을때속성 선언을 간결하게 한다.

 

class MyClass

{

public double TotalAmount { getset; }

public string Name { getprivate set; }       // read-only

public int CustomerId { getprotected set; }  // read-only for user, writable for drived class

}

 

Extension Methods

인스턴스 메서드 구문을 사용하여 호출할 수 있는 정적 메서드를 사용하여 기존 클래스를 확장합니다.

 

public static class MyExtensions {

    public static int WordCount(this String text) {

        return str.Split(new char[] { ‘ ‘, ‘.’, ‘?’, StringSplitOperations.RemoveEmptyEntries).Length;

    }

}

String s = "New Features in C# 3.0";

int wordCount = s.WordCount();

 

Lambda expression

대리자나 식 트리에 바인딩할 수 있는 입력 매개 변수를 가진 인라인 식을 사용할 수 있게 합니다

 

Func<intint> myPower2 = x => x*x;

int x2 = myPower2(5); // x2 = 25

 

Partial methods

Abstract class의 abstract method와 유사한 효과를 나타낸다몇가지 제한사항이 있음

// define in file1.cs

partial void onNameChanged();

// define in file2.cs

partial void onNameChanged()

{

    
}

 

 

C# 3.0 기능 중에 몇 가지는 코딩 시에 작업을 수월하게 하고코드 분석을 쉽게 해 주는 문법적인 발전도 있고, Lambdaexpression과 같이 동적 표현이 가능케 해주는 획기적인 기능도 추가되었습니다 (lambdaexpression은 다음에 얘기할 LINQ에서도 설명할 예정입니다.)

 

요즘 Resharper 4.1 이상을 깔면 추천 코드를 제공해 주는데특정 타입을 “var” 예약어로 바꾸는 것을 추천하는 경우가 많습니다. “var”라는 것이 어찌보면모든 수형을 표현하는 것처럼 보이므로 COM+에서 여러 Language에서 상이한 수형을 표현하기 위한 VARIANT를 연상할 수 있는데실제 var는 동적으로 수형이 결정되는 VARIANT 와는 달리 컴파일시에 결정됩니다. C# 코드상에서만 결정이 안되었지컴파일된 IL Code 상에서는 실제 수형으로 선언되고사용되고 있음을 알수 있습니다.

 

아래 원본 C# 코드와Reflector를 통한 diassembling 된 코드를 비교해 보십시요.

“var”, “object initializer” 를 이용하게 되면아래와 같이 약간의 변형을 거쳐지만원하는 결과가 되는 것은 마찮가지 입니다.

// C# 코드

public virtual Config CreateConfig(string section, string name, string value)

{

        var config = new Config(name, value)

                               {

                                       Application = AdminContext.Current.Application,

                                       Enterprise = AdminContext.Current.Enterprise,

                                       Section = section,

                                       IsEnabled = true

                               };

 

        Session.SaveOrUpdate(config);

        return config;

}

// Deassembler code
public virtual Config CreateConfig(string section, string name, string value)
{
    Config <>g__initLocal7 = new Config(name, value);
    <>g__initLocal7.Application = AdminContext.Current.Application;
    <>g__initLocal7.Enterprise = AdminContext.Current.Enterprise;
    <>g__initLocal7.Section = section;
    <>g__initLocal7.IsEnabled = true;
    Config config = <>g__initLocal7;
    this.Session.SaveOrUpdate(config);
    return config;

}




Deassembled code에서 보듯이 var Config 수형으로 선언되어 있습니다확실히 VARIANT 수형과는 다른 것입니다. (C# 4.0 spec에 보면 dynamic language 기능이포함되는데이때는 기존 variant와 비슷한 수형이 나올것입니다.)

 




다음으로 .NET Framework 3.0 부터 아주 새로운 개념이 추가 되었는데LINQ (Language INtegrated Query) 입니다.

이 부분에 대한 자세한 설명은 MSDN에 있으니 참고하시고다른 글로서 설명을 드리겠습니다.

 

이 글에서는 LINQ의 기본적인 문법을 설명하고위의 C# 3.0 에서 추가된 특징이 어떻게 활용되는지 (반대로 LINQ 라는 개념을 구현하기 위해 C# 3.0의 새로운 기능들이 만들어졌다라고 볼 수 있습니다.)

 

LINQ를 사용하는데는 크게 두가지 방식이 있습니다.

 

1.     Query Expression ( SQL 문과 비슷 )

2.     Query Operator (Extension Methods 사용)

 

우선 2가지 방식의 예를 봅시다.

 

1.     Query Expression

 

Query Expression은 우리가 잘 알고 있는 Database 질의 형식과 유사하다 SQL 문법과 유사하게 사용할 수 있고기본적으로 메모리에 적재된 Object들로부터 질의를 수행하고결과를 받을 수 있다. (물론 LINQ to SQL, LINQ to XML 등 다양한 질의 대상이 추가될 수 있다)

 

표 4. Query Expression Format

 

from [ type ] id in source

join [ type ] id in source on expr equals expr [ into id ] ]

from [ type ] id in source | let id = expr | where condition }

orderby ordering, ordering, … ]

select expr | group expr by key

[ into id query ]

 

 

Query Expression 예를 들어 보자.

 

코드 1. Query Expression Sample


예제 코드는 시스템에 수행중인 모든 프로세스 중에 메모리가 20Mb 이상을 사용하는 프로세스를 찾아사용하는 메모리 양을 기준으로 정렬을 수행하고그 프로세스의 속성 중에 Id, Process Name 만으로 새로운 anonymous type을 생성해서 반환하도록 한다.

 

기존 코드로 이 작업을 수행하려면, Filtering, Sorting, 새로운 Class 정의 등 상당히 많은 코드를 구현해야 하지만예제 코드를 사용하면 (질의 문법에 약간이라도 익숙하다면직관적이고코드도 상당히 간단해 진다.

 

 

2.     Query Operator

Query operator query expression과는 달리메소드 호출을 이용하여 질의를 수행하므로기존 C# Language 문법과 유사하다.다만 C#의 새로운 특징인 (사실 새로운 기능이 아니더라도 가능하게 할 수는 있다. – Nhibernate ICriteria, DetachedCriteria가 그런 경우이다.) extension methods 를 이용하여코드를 일목요연하게 표현 할 수 있다.


 코드 2. Query Operator Sample

 

Query expression과 같은 작업을 수행하는 코드지만기존 C# 코드와 큰 차이가 없다다만 Lambda expression에 대한 공부는 좀 해야겠지요

 

두 예제 모두 붉은 글자로 코드상에서 사용된 C# 3.0의 새로운 특징을 명시했습니다많은 특징들을 LINQ가 이용하므로여러분 중LINQ를 쓰시고자 한다면, C# 3.0의 새로운 특징들을 먼저 공부해야 합니다물론 이러한 새로운 특징들이 꼭 LINQ 기술을 쓸 때만 유용한 것은 아니고전통적인 코드상에서도 상당한 잇점을 제공합니다.

 

그럼 이 두 가지 방식 중에 어떤 걸 이용해야 할까요?

답은 당신 맘대로” 입니다.

 

그럼 넌저요 Query operator 방식을 더 선호합니다.

이유는?

뭐 여러가지가 있겠지만가장 먼저 생각나는 건 메소드 사용이 익숙하고이해하기에도 더 쉽거든요.

또다른 큰 이유는 Query Operator는 확장이 가능하지만, Query expression은 예약어 방식이라, MS 말고는 확장이 곤란합니다.

 

 5.에서는 Query operator와 expression 간의 대응관계를 표시하고 있는데실제 예약어 방식인 query expression에서는 제공하지 않는 부분이 많습니다다만 query operator의 메소드 명이 제게는 직관적이지 않은 부분은 불만입니다.

 

 

 

표 5. Query Operator & Expression

Operator

Expression

Operator

Expression

All

N/A

OrderBy

Orderby …, …

Any

N/A

OrderByDescending

Orderby …, … descending

Average

N/A

Select

Select

Cast

From int I in numbers

SelectMany

Multiple from clauses

Count

N/A

Skip

N/A

Distinct

N/A

SkipWhile

N/A

GroupBy

Group … by … [ into …]

Sum

N/A

GroupJoin

Join … in … on … equals … into …

Take

N/A

Join

Join … in … on … equals …

TakeWhile

N/A

LongCount

N/A

ThenBy

Orderby …,…

Max

N/A

ThenByDescending

Orderby …,… descending

Min

N/A

Where

Where

 

 

 

 

 

이제까지 C# Language의 버전별 새로운 특징을 살펴봤고마지막에는 LINQ에 대한 간략한 소개를 했습니다앞서 설명했지만새로운 버전으로 Upgrade시에는 새로운 기능이 뭐가 있고어떤 장점이 있는지 파악하고 선택적으로 사용하는 것이 우선입니다특히나 C# Language 는 가장 기본이 되는 특성이므로꼭 알아둬야 하고자신의 것으로 만들 필요가 있습니다.

'IT > C#' 카테고리의 다른 글

C#2.0 Iterators,Partial 클래스,Nullable 타입  (0) 2009.10.07
닷넷 트랜잭션 정리  (0) 2009.09.30
C# 3.0 개요  (0) 2009.09.11
[C# 2.0] Generics, Iterator, Anonymous, Partial  (0) 2009.08.24
[.net Framework] System.Activator 객체  (0) 2009.08.24
posted by 방랑군 2009. 9. 15. 14:02


 아 정말 쓸데없는 말이 덕지 덕지 있어서 먼지 알기 힘들었다....


 NUNIT ...TDD... 등등..

 한마디로 프로그램 만든 함수 CALL 해서 테스트 하는 프로그램(TEST FRAMEWORK) 이다.  함수 엄청 많고 DLL 등 해당 함수까지 가서 디버깅 힘드니까 나온 툴이라 생각하면 된다..  

 참나, 살이 덕지 덕지 붙어서 이론이 되어버려 먼가 큰거라 생각하게 만드는 상태까지 와서 먼지 알려고 엄청난 사이트 뒤지고 시간 낭비하고 테스트도 해봤다 --;
 짜증나게 이렇게까지 간건 테스트 샘플도 먼가 있어보이게 만들어 버려 --;

걍 프로그램 만들어서..
클래스에 [TestFixture] 해주고 테스트할 함수에 [Test] 주고
 NUNIT 에서 주는 프로그램 nunit.exe 실행하고 VS.NET 에서 프로세스 디버거로 nunit.exe 이거 디버그 모드 실행해서 nunit.exe 에 해당 EXE, DLL 불러와서 
[TEST] 함수 실행해서 디버깅 하면 된다.

아 순서 정리해서 쓰기 힘드네.. 솔직히 짜증이다...


 

using System;
using NUnit.Framework;

namespace WindowsApplication2
{
/// <summary>
/// Class1에 대한 요약 설명입니다.
/// </summary>
/// 

[TestFixture]
public class Class1
{
[Test]
public void BagMultiply() 
{

Assert.AreEqual(1,1,"TEST");

Console.Write("TEST");

}
}
}



'GET > Test FW' 카테고리의 다른 글

TDD : NUnit, MbUnit 그리고 xUnit 활용 범위...  (0) 2009.09.15