2008. 10. 16. 21:36

가비지 컬렉션의 동작원리


닷넷의 가바지 컬렉터가 작동하는 원리를 알아보자~ 메모리 할당, 메모리 관리, 메모리 해제로 크게 나누어
볼 수 있으며 메모리 할당은 일반적인 Heap과 마찬가지로 다음 할당할 포인터 위치를 가지는 포인팅을 하고
새 객체가 생성되면 그 객체의 크기를 조사하여 managed heap의 공간이 충분한지를 검사하게 된다.
만일 충분한 공간이 있다면 연속적으로 메모리 할당이 이루어지고 이러한 연속적인 메모리 할당을 통해
객체들끼리의 따른 접근속도가 빠른 이점을 가질 수 있는 것이다.( 비슷한 시기에 생성된 객체들은 인접한
공간에 할당되기 때문에 접근속도가 용이하다. )
 
할당과정을 간력히 적어보면

프로세스 초기화 -> 주소 공간 예약 및 포인팅 -> 객체생성 -> 새 객체의 메모리 용량 계산 -> 힙메모리 여유 공간 조사 -> 예약된 메모리 영역에 객체 할당 -> 다음 객체 포인터 이동

으로 요약된다.

메모리 관리를 위해서 가비지 컬렉터는 3가지의 세대로 분리하여 관리한다. 즉 매번 가비지 컬렉션 대상을 위해
모든 managed heap영역을 다 검사하지 않는다는 것이다. 실제로 모든 영역을 때마다 계속 하게되면 프로세스
구동에 있어서도 성능의 저하가 눈에 보이게 된다고 한다. 다시 돌아와서 CLR은 Heap영역을 0,1,2세대로 나누어서 관리한다고 했다. 객체가 제일처음 생성되면 0세대로 분류되고 다음 가비지컬렉션이 발생하여 쓰지 않는 메모리를 검사하는 과정에서 살아남은? 객체는 1세대로 올라가게 된다. 이렇게 하여 최대 2세대까지 올라갈 수 있게
되고 예로 main에서 쓰이는 객체경우 중간에 호출되는 메소드내의 객체보다는 오래 살 가능성이 크기 때문에
2세대까지 올라가는 경우가 많다고 생각하면 이해가 쉬울것이다.

결국 가비지 컬렉터는 할당하고자 하는 객체의 메모리 크기가 모자랄 경우 0세대를 검사하여 가비지를 골라내고
만일 이러한 한번의 과정을 통해서도 메모리의 부족할 경우 1세대에 대한 가비지 대상을 검사하게 된다. 이때
1세대를 검사할때는 그 밑의 세대인 0세대도 같이 수행하는데 이를 보면 결국 2세대까지 올라가서 검사를 한다는
것은 모든 managed heap영역을 검사한다는 말이 된다. 실제로 2세대까지 올라가서 검사하는 경우는 거의 없다고 한다.

0세대 가비지 수집 -> 메모리 부족 -> 1세대 가비지 수집(0세대 동반) -> 메모리 부족
-> 2세대 가비지 수집(1,0세대 동반)

그러면 가비지 수집은 어떻게 하는 것일까? 참조 경로에 대한 정보를 수집하는 것이다. 참조경로는 그럼 누가
될까? 참조경로는 첫번째 시작점으로 전역 객체나 정적 객체에 대한 참조가 루트가 된다. 또한 스택에 있는
지역변수, 매개변수의 객체 참조등도 루트가 될 수 있다. 이러한 참조를 이용하면 참조계수를 이용한 방법보다
안정적으로 사용할 수 있고 이렇게 참조정보를 수집한 그래프를 통해 참조 당하지 않는 객체를 가비지로 판단하는
것이다.

루트를 통해 참조 그래프를 생성하고 여기에 나타나는 않는 객체를 가비지가 된다. 이 객체에 대해서는 메모리 해제가 일어난다. 가비지 대상으로 표시된 영역에 대해 유효한 객체를 차례대로 재배치함으로써 덮어버리면서 연속적인 메모리 구조를 유지한다. 85KB이상의 큰 객체는 LOH( Large Object Heap )이라는 곳에 할당되고 이 영역은 재배치 하지 않는다. 너무 크기가 크기 때문에 재배치 자체가 메모리의 비효율을 가지고 오기 때문이다. 그 다음 살아남은 세대는 다음 세대로 올라가게 되고 최대 2세대까지 올라갈 수 있다고 했다. 가비지 컬렉션이 완료되면
다음 새 객체의 할당을 위해 빈 메모리의 시작주소를 새로 지정해 주게 됨으로써 모든 작업이 끝난다.

가비지 컬렉션 수행절차를 간략히 보자~

객체 그리프 생성 및 유효한 객체 추적 -> 가비지 객체 결정, 표시 -> 메모리 재배치( Memory Compaction ) -> 객체참조 값 조정 -> 유효 객체에 대한 세대 상승 -> 새로운 포인팅 

ps. '사랑하지 않으면 떠나라'인가..라는 책을 보면 저자가 인도의 개발자들을 뽑을 때 면접질문이 C#코딩으로 가비지 켈렉션을 뻗게 하는 방법이 어떤 것이 일을까? 라는 질문을 많이 했었다고 한다. 그때 제대로 틀린말조차
하는 사람이 없었다고 한다. 이러한 내부에 대한 이해가 없이 프로그램을 개발하는 경우가 많은 이때 여러 생각을 하게 했던 대목이였다.ㅎㅎ 이때쯤 한번씩 생각해보기 바란다. " C#코딩으로 가비지 켈렉션을 뻗게 하는 방법이 어떤 것이 일을까?"

참조 : 마소2008.04
2008. 10. 16. 19:58

가비지 컬렉션의 개념

닷넷환경에서 개발할 때 가장 큰 강점중에 하나가 가비지 컬렉션덕분에 메모리를 관리하지 않아도 된다는
점이다. C/C++기반의 프로그램을 개발하면 메모리 누수, 현수 포인터( 사용중인 객체가 해체되는 문제 ), 객체 손상등의 문제가 생길 수 있으며 이러한 위험적 요소를 직접 개발자에게 맡기지 않고 시스템에게 맡기는 것이
핵심이라고 할 수 있다.

닷넷의 공통 실행환경인 CLR( Common Language Runtime )은 가비지 컬렉터라는 일종의 백그라운드
서비스를 동작시켜 불필요해진 메모리 공간을 추적하고 여유공간을 확보해준다.

프로그램이 실행되기 위해서는 메모리에 관련된 데이터들이 올려져야하는 것은 당연한 이야기이다. 메모리를 보면
Code영역에 명령어
Data영역에 전역변수,static변수
Stack영역에 지역변수, 함수의 매개변수
Heap영역에 개발자에 의해 할당된 메모리영역

이라고 할 수 있다. 여기서 닷넷 응용프로그램은 CLR에 의해 직접 관리하는 Heap( managed heap )이 추가된다.
이렇게 되면 관리되는 Heap( managed heap )과 관리되지 않는 Heap( unmanaged heap )으로 나누어지게 되고
관리되지 않는 Heap에는 C/C++환경에서 동적으로 할당된 영역과 Win32 API, COM객체등이 대부분 이영역에
할당된다.

정리하자면 관리되는 Heap이란 닷넷 실행환경에서의 객체가 할당되는 메모리 공간으로 CLR에 의해 직접 관리되는 메모리 영역을 뜻한다.

참조요약 : 마소2008.04
2008. 10. 3. 17:21

[펌] 주의해야할 기본문법들


이번은 C#이라는 언어를 사용해서 개발하다 보면 언어의 문법 상 조금 주의를 기울여야하는 부분들이 있습니다.
이런 부분들에 대해서 정리를 한번 해보았습니다.

C# Description 1

값 형식 변수는 Stack에 저장되고 참조형식 변수는 Heap에 저장된다.
구조체 및 열거형은 값형식이고 object, string 형은 참조형식이다.
String은 참조형 이지만 동일한 문자열을 가리키는 두 문자열 변수에서 하나를 변경하더라도 다른 하나에는 영향을 미치지 않게 Heap에 별도의 새로운 객체를 할당하게 된다.

[값 형식]
모든 값 형식(Value-Type) 변수는 사용 전에 초기화되어야 한다.
Decimal 형식은 통화량 표시등 금융 계산을 위해 사용되면 Type문자는 M이다.
Char 형은 16비트(유니코드) 문자를 나타낸다.
값 형식이 참조형식에 비해 장점
빨리 할당된다.
변수는 범위에서 벗어나면 자동으로 메모리에서 해지된다.
복사하기 쉽다(=)
구조체 :
구조체는 new 연사자를 사용하지만 new를 호출하기 전에도 실제로 사용가능하고, 이것의 필드에 접근할 수 있다. 구조체는 선언되자마자 초기화될 수 있는데 모든 필드들은 기본값이 0으로 초기화된다. 하지만 컴파일러는 new 키워드를 이용하여 처음 초기화를 시켜주지 않거나 모든 필드의 값을 설정해 주지 않으면, 구조체를 복사하거나 이것의 필드값을 읽을 수 없도록 막고 있다.
구조체의 모든 멤버 데이터는 기본적으로 private이다.
클래스와는 달리 구조체의 인스턴스는 메모리상에 별도의 장소에 할당된다.
구조체의 인스턴스는 스택의 공간을 차지하기 때문에 상대적으로 작은 크기의 객체를 표현하는데 적합하다. 모든 값 데이터 형식을 구현하는데 사용된다.
프로그래머는 다른 함수의 매개변수로 전달해야 하는 값을 한데 묶기 위해 구조체를 사용하는 경우가 대부분이다.

[참조형식]
클래스, 인터페이스, 델리게이트, 배열 등

클래스 : 대부분의 실행파일은 적어도 하나의 클래스를 가지고 있는데 이것은 프로그램의 진입점인 Main 메소드를 가지고 있다.

인터페이스 : 클래스를 구현하는 기능성을 정의하는 데 사용, 프로퍼티, 메소드, 이벤트, 인덱서(Indexer)를 포함할 수 있으나 인스턴스화 될 수 없고, 함수들의 구현을 정의하지 못한다.

델리게이트 : 메소드를 참조하는 데이터 형식, 인스턴스화되어 클래스의 정적메소드나 클래스의 특정 인스턴스의 메소드들을 호출하는데 사용될 수 있다. 실행시에 어떤 메소드를 호출하고자 하는지 결정할 수 있다.

배열: 배열을 초기화하지 않고 선언할 수 있게 때문에 프로그램상에서 동적으로 크기를 변경할 수 있다.
Int[] Integers;
Integers = new int[32];
C# 배열은 다른 C# 객체처럼 CLR에 의해서 관리되기 때문에, 더 이상 참조되지 않으면 자동으로 소멸한다.
아래의 방법으로 초기화 하는 경우, 변수를 사용하여 배열의 크기를 명시하는 것이 불가능


int len=3;
//Not Permitted
string[] String = new string[len] { “first element”, “second element”, “third element”}< /FONT >


하지만 상수는 사용할 수 있다.


Const int len=3
// Permitted
string[] String = new string[len] { “first element”, “second element”, “third element”}< /FONT >


[Type Conversion]
암시적 형변환 : 데이터 형식끼리의 변환은 값이 변하지 않는다는 보장이 있으면 자동으로 이루어 질 수 있다.(short, int 값은 문제없이 long 변수에 대입될 수 있다.)
문자열을 숫자형식으로 바꾸고 싶으면 Parse 메소드 사용

Boxing & UnBoxing
박싱 : 값 형식을 참조 형식으로 변환(값 형식을 object 형식으로 캐스트)
언박싱 : 참조 형식을 값 형식으로 변환

언박싱은 반드시 명시적으로 행해져야 한다.

[변수]
public static int x=10, y=20 //x, y는 둘다 public static int 이다.
Public int x=10, private byte y = 2 //Not Permitted
같은 범위(Scope) 내에서는 같은 이름을 가진 변수들이 선언될 수 없다.


//Permitted
for(int i = 0; i < 10 ; i++)
{
i의 범위는 여기서 끝남
}
using System;
public class ScopeTest
{
static int j = 20; //필드(Field)
public static int Main()
{
int j = 30; //지역변수
Console.WriteLine(j); //30
return 0;
}
}
for(int i = 0; i < 10 ; i++)
{}


변수 한정자
지역변수가 아닌 필드에만 사용가능
- internal : 현재 프로그램에서만 변수에 접근 가능
- new
- private
- protected
- protected internal : 현재 프로그램이나 현재 데이터 형식에서 파생된 데이터 형식으로부터 변수에 접근가능
- public
- readonly : 변수를 일단 한 번 초기화하면 값을 수정할 없다.
- static : 클래스의 인스턴스가 몇 개 생기는가와 상관없이 필드에 대한 하나의 복사본만 생긴다.

상수 : 정적 읽기전용 필드와 유사
필드뿐 아니라 지역변수도 상수로 선언가능
상수는 반드시 선언 시 초기화되어야 한다.
상수는 컴파일시 계산 가능해야 하므로 어떤 변수가 가진 값으로 초기화할 수는 없다.
상수는 항상 Static이다.(static 한정자를 추가할 필요 없음)

[연산자]
Checked & Unchecked
CLR의 스택 오버플로우 처리 방식을 설정
코드의 블록을 CLR은 강제로 오버플로우 체크하고, 오버플로우가 일어나면 예외를 발생시킨다.
Is
Sizeof : 스택에 저장된 값 형식의 크기를 바이트 단위로, 안전하지 않은 코드에서 사용가능

unsafe
{
console.writeline(sizeof(int));
}


typeof : 특정한 데이터 형식을 나타내는 Type 객체를 반환


foreach문 : IEnumerable 인터페이스를 지원하는 컨테이너 클래스의 각 항목들에 대해서 명령문을 수행하는 것이다.

Using 문 : 리소스를 많이 차지하는 객체를 사용한 후에 즉시 처리한다.
Using(object)
{
//object를 사용하는 코드
}
object는 IDisposable 인터페이스를 구현하고자 하는 클래스의 인스턴스이다. IDisposable 인터페이스를 구현하는 모든 클래스는 반드시 Dispose 메소드를 구현해야 한다. Dispose 메소드는 using 블록이 끝나자마자 호출된다.

[메소드]
메소드 한정자
- new : 메소드는 동일한 signature를 갖는 상속받은 메소드를 숨긴다.
- virtual : 메소드는 파생 클래스에 의해 오버라이드 될 수 있다.
- Abstract : 메소드의 signature를 정의하지만 구현은 제공되지 않는 가상 메소드(virtual method)이다.
- Override : 메소드는 상소된 가상 메소드나 추상 메소드(abstract method)를 오버라이드 한다.
- Sealed : 반드시 override와 함께 사용, 이 클래스를 상속받는 클래스에 의해서는 오버라이드될 수 없다.
- Extern : 메소드는 외부에 다른 언어로 구현이 되어 있다.
메소드의 입력인수
기본적으로 인수는 값으로 메소드에 전달된다. (Pass By Value), 하지만 참조변수가 전달되면 참조가 전달되므로 메소드 내부에서 변경시 외부 참조 변수에도 영향이 미친다.
ref 키워드를 이용하여 값 형식 인수를 참조형식으로 전달 가능

Static void somefunc(int[] Ints, ref int i)
{}
//메소드 호출시에도 ref를 붙여주어야 한다.
Somefunc(Ints, ref i);

out : 출력매개변수, C#에서는 변수가 참조되기 전에 반드시 초기화되어야 한다, 메소드의 입력 인수 앞에 out 키워드를 붙이면 초기화하지 않은 값을 메소드로 전달할 수 있다.

형식문자열 (format string)
- C: 현재의 통화 형태
- D: 10진수
- E: 지수적 표현
- F: 부동 소수점 형태
- G: 일반적 형태
- N: 숫자 형태
- P: 퍼센트 형태
- X: 16진수
- #: 어떤문자도 없으면 무시된다.
- 0: 그 자리에 어떤 값이 있으면 그 값에 해당하는 문자로 대치되고, 아무런 값도 없으면 0으로 출력된다.

출처 : http://www.ensimple.net/enSimple/

2008. 10. 3. 17:21

[펌] 어트리뷰트(Attribute)


 어트리뷰트

Attribute는 클래스안에 메타정보를 포함 시킬수 있는 기술로서 클래스, 데이터 구조, 열거자 그리고 어셈블리와 같은 프로그래밍적 요소들의 실행시 행동에 대한 정보를 기술 할 수 있다.

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

어트리뷰트 역시 클래스의 일종이다.

어트리뷰트의 문법은 다음과 같다.
[attribute(positional_parameter, name_parameter = value, …) ]
파라미터에는 두 종류가 있는데 하나는 위치지정 파라미터로 반드시 들어와야 한다. 명명파라미터(name_parameter)는 꼭 필요하지는 않은 구조를 가지면 어트리뷰트 안에 추가적인 정보를 넣을 때 이용한다.

예를들면

[AdditionalInfo(“2004-01-01”)]
public class Test { ..}

원하는 프로그래밍 요소 위에 Attribute를 써주면 그곳에 Attribute가 배정되는 것이다.

1.Conditional Attribute
C# 디버깅을 지원하기 위해 Conditional Attribute를 사용 할 수 있다. Conditional Attribute는 사용자가 정의 한 값에 의해서 해당 메소드를 실행 하도록 한다.

#define SOUNDCARD // 이 부분을 지운 후 실행 해 보자
using System;
using System.Diagnostics;

class Test
{
        //Conditional Attribute인 경우 지정된 위치지정 파라미터가 정의 되어
        //있을때 실행이 되는 것이다.
        [Conditional ("SOUNDCARD")]
        static void print()
        {
                Console.WriteLine("도레미...");
        }

        static void Main()
        {
                print();
        }
}

위 예제에서 #define SOUNDCARD 부분을 지우지 않은 상태에서는 도레미... 가 정상적으로 출력 되지만 지운 상태에서는 출력 되는 않는다.

Conditional Attribute는 클래스나 구조체 안에 있는 메소드 에서만 사용 할 수 있다. 또 그 메소드는 void 형 이어야 한다. 다음의 예문처럼 메소드에 대해 여러 Conditional Attribute를 붙이게 되면 그 중 하나만 위치지정 파라미터가 정의 되어 있어도 그 메소드를 실행 시킨다.

만약 두개의 Conditional Attribute를 모두 만족해야 메소드를 실행 할려면 아래와 같은 방법을 이용하면 된다.

[Conditional(“MODEM”), Conditional(“ADSL”)]
static void print() { .. }

#define SOUNDCARD
#define SPEAKER

using System;
using System.Diagnostics;

class Test
{
        
        [Conditional ("SOUNDCARD")]
        static void isSound()
        {
                isSpeaker();
        }

        [Conditional ("SPEAKER")]
        static void isSpeaker()
        {
                Console.WriteLine("음악을 들을 수 있습니다...");
        }

        static void Main()
        {
                isSound();
        }
}

[결과]
음악을 들을 수 있습니다...

2.DllImport 어트리뷰트
DllImport Attribute는 C#안에서 Unmanaged Code를 사용 할 수 있게 한다. Unmanaged Code란 닷넷 환경밖에서 개발된 코드를 가리킨다. DllImport Attribute는 System.Runtime.InteropServices 네임스페이스 안에 정의 되어 있다. 사용방법은 위치지정 파라미터로 사용 할 DLL 파일을 인자로 넘겨 주면 된다.

using System;
using System.Runtime.InteropServices;

class Test
{
        //User32.dll 파일안의 MessageBox 함수를 불러와서 사용하는 예이다. DllImport Attribute를
        //이용하여 사용할 코드가 포함되어 있는 DLL을 넘겨주고 extern 키워드를 통해 사용하려고 하는
        //메소드가 외부에 있음을 알린다. 이렇게 하면 닷넷 환경 밖에서개발된 코드들도 C#안에서 쓸수 있다.
        [DllImport("User32.Dll")]
        public static extern int MessageBox(int h, string m, string c, int type);

        static void Main()
        {
                MessageBox(0, "Hello!", "In C#", 0);  //다이얼로그 창의 타이블이 "In C#" 이며 내용은 "Hello"
        }
}


3.Custom Attribute의 정의

-어트리뷰트의 범위 지정

앞에서 Conditional Attribte는 메소드에만 붙일 수 있다고 했다. 그렇다면 사용자가 만든 어트리뷰트에 대해 어떤 곳에서만 붙일 수 있게 하는 방법은 없을까? AttributeUsage를 이용해서 사용자가 정의한 데이터 형에만 어트리뷰트를 붙일 수 있다.

[AttributeUsage(AttrbuteTargets.Method)]
public class AdditionalInfo { … }

AttributeUsage 역시 Attrbute 이며 사용자가 정의할 어트리뷰트 앞에 사용됨으로서 범위를 지정 할 수 있다. Method 이외에 AttrbuteTargets.Class, AttrbuteTargets.Delegate, AttrbuteTargets.Interface, AttrbuteTargets.Propert, AttrbuteTargets.Construct 등등을 사용 할 수 있다.

만약 여러 개의 데이터 형에 붙일려면 ‘|’를 이용하면 된다.

[AttributeUsage(AttrbuteTargets.Method | AttrbuteTargets.Delegate)]
public class AdditionalInfo { … }

또한 모든 데이터 형에 붙이는 것을 가능하게 할려면 AttrbuteTargets.All 이라고 해 주면 된다.

-어트리뷰트 클래스 선언

간단히 클래스에 대한 제작자, 업데이트 날짜, 최신 버전을 다운 받을 수 있는 곳등의 정보를 담을 수 있는 어트리뷰트를 만들어 보도록 하겠다. 다른 클래스를 만드는 것처럼 비슷하게 클래스를 작성 하면 어트리뷰트가 구현된다. 모든 어트리뷰트는 System.Attribut로부터 상속 받는다. 즉 보통 클래스를 선언하는 똑 같은 방법으로 선언하고 다만 System.Attriute로부터 상속을 받으면 그 클래스가 어트리뷰트가 되는 것이다. 일반 클래스와 구분하기 위해 접미사로 ‘Attribute’를 붙일 것을 권고 한다.

어트리뷰트도 클래스 이므로 생성자가 존재 한다. 다만 어트리뷰트는 하나의 생성자만 가질 수 있다. 즉 생성자 오버로딩이 불가능 하다. 그럼 추가로 받아야 하는 정보들은 어떻게 처리 할까? 어트리뷰트에서는 생성자에서 꼭 집어 넣어야 하는 데이터는 위치지정 파라미터로 받고 부가적인 데이터는 명명 파라미터를 통해 받아 들임으로서 문제를 해결 한다.

[예제]
using System;

[AttributeUsage(AttributeTargets.Class)]
public class AdditionalInfoAttribute: Attribute
{
        //생성자에 있는 두개의 인자는 위치지정 파라미터 이다.
        //즉 위치지정 파라미터는 클래스에 어트리뷰트를 붙일때 반드시 넘겨 줘야 한다.
        //항상 생성자에서 값을 넘겨 주게 되어 있으므로 name, update인 경우 Property에서
        //set이 없다.
        public AdditionalInfoAttribute(string name, string update)
        {
                this.name = name;
                this.update = update;
        }

        public string Name
        {
                get { return name; }
        }

        public string Update
        {
                get { return update; }
        }

        public string Download
        {
                set { download = value; }
                get { return download; }
        }

        string name;
        string update;
        string download;
}

// 아래의 경우처럼 위치지정 파라미터는 생성자에 값을 그대로 전달하지만 명명 파라미
// 터는 파라미터 이름에 값을 대입하여 생성자에 넘겨야 한다.
[AdditionalInfo(“jclee”,’2004-01-01”, Download = http://www.oraclejava.co.kr)]
class Test { … }


클래스에 어트리뷰트를 붙였다면 반대로 클래스로부터 어떤 어트리뷰트들이 붙어 있는지 아는 하는 방법도 있어야 할 것이다. 바로 전 예제에서 Test라는 클래스에 어트리뷰트를 붙였는데 반대로 Test라는 클래스로부터 어트리뷰트 정보를 알아내는 방법을 예제를 통해 보도록 하자.

public class AttrInfo
{
        public static void Main()
        {
                Type type = typeof(Test);

                foreach(Attribute attr in type.GetCustomAttributes(true))
                {
                        AdditionalInfoAttribute info = attr as AdditionalInfoAttribute;

                        if (info != null)
                        {
                                Console.WriteLine("Name={0}, Update={1}, DownLoad={2}", info.Name, info.Update, info.Download);
                        }
                }
        }
}

4.사용자정의 어트리뷰트의 처리 과정

-어트리뷰트 클래스를 찾는다.
-어트리뷰트의 범위를 체크 한다.
-어트리뷰트의 생성자를 체크 한다.
-객체의 인스턴스를 생성 한다.
-명명 파라미터들을 체크 한다.
-명명 파라미터 값으로 필드나 프로퍼티의 값을 설정 한다.
-어트리뷰트 클래스의 현재 상태를 저장한다.

5.Multiple Attribute의 사용
한 개의 프로그래밍 요소에 한 개 이상의 어트리뷰트를 붙일 수 있다.

public class Csharp {
        [Conditional(“CLR”)]
        [FAQ(http://www.help.com/chapter1)]
public void chapter1() { … }
}

한 개의 프로그래밍 요소에 여러 개의 어트리뷰트를 붙일 수 있지만 앞에서 만든 AdditionalInfoAttribute를 아래 처럼 중복해서 사용하면 오류가 발생 한다.

[AdditionalInfoAttribute(“jclee”,”2004-01-01”, Download=http://www.oraclejava.co.kr)]
[AdditionalInfoAttribute(“tatata”,”2004-02-01”, Download=http://www.oraclejava.co.kr)]
class OracleJava { … }

어트리뷰트는 기본적으로 한 어트리뷰트에 한 개의 인스턴스만 사용 가능하지만 AllowMultiple을 true로 지정하면 위에서와 같이 같은 어트리뷰트를 여러 개 사용 가능하다.


6.어트리뷰트로부터 값 얻어오기
-클래스 메타 데이터
여기서는 Reflection을 이용하여 값을 얻어오는 것을 살펴 보도록 하자. 닷넷 프레임 웍에서는 메타데이터를 검사 할 수 있는 클래스들이 포함된 System.Reflection 이라는 네임스페이스를 제공 하고 있다. 이 Reflection 네임스페이스 안에 있는 MemberInfo 라는 클래스는 클래스의 어트리뷰트를 알아볼 때 유용하게 사용 될 수 있다. System.Type 객체의 GetMembers 라는 메소드를 적절히 구사하여 클래스 메타데이터 를 조사 할 수 있다.

System.Reflection.MemberInfo[] members;
Members = typeof(MyClass).GetMembers();


-어트리뷰트의 정보 얻기
MemberInfo 객체는 GetCustomAttributes 라는 메소드를 가지고 있다. 이 메소드는 모든 어트리뷰트의 정보를 배열로 알아 낼 수 있다. 이렇게 알아낸 정보를 반복문을 이용하여  어트리뷰트를 조사 할 수 있다.

 

출처 :  http://cafe.naver.com/itclean.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=1098

2008. 10. 3. 17:20

[펌] CTS(Common Type System)와 C#의 자료형(Value-Type, Reference-Type)

CTS(Common Type System

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

• CTS supports object-oriented and Procedural languages.

• CTS supports both value and reference types

 

좀더 알아보면 CTS 는 닷넷 프레임워크에서 동작하는 모든 프로그래밍 언어(C#, VB.Net, J#)들이 쪽같은 데이터형식을 사용하도록 해주는 것입니다.

(System.Int32라는 클래스는 CTS에서 제공하는 int 형입니다. 이것은 닷넷에서의 어떠한 개발언어에서도 사용이 가능 합니다.)

모든 데이터형식들은 기본적으로 객체에서 파생되었으며 Value type 은 객체 형식을 포장 (sealing) 해 놓은 개념 입니다.

 

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

Value-Type, Reference-Type

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

Value-Type

CTS 에서는 value type 과 reference type 을 지원하는데 Value type 변수들은 데이터를 직접 가지고 있습니다 .예를들어 int i=10 이라고 쓰면 i 변수에는 10 이 직접 들어 있는 것입니다. int j=i 라고 하면 i 의 값이 j에 복사되어 들어 가는 것입니다.(다아시는거죠^^), 자바에서의 기본 자료형과 같은 겁니다. Value-Type은 Built-in Type과 User-Defined Type 두가지가 있습니다. int, long, float, double 등은 Built-in Type 이고 struct, enum등은 User-Defined Type 입니다.

 

Reference-Type

데이터를 직접 저장하는 것이 아니라 레퍼런스(참조값)을 저장 합니다.(Store references to their data) 그러므로 두개의 레퍼런스형 변수는 같은 데이터(오브젝트)를 지칭하는 것이 가능 합니다.( Two reference variables can reference same object) 물론 같은 것을 서로 쳐다 볼수 있으므로 한쪽에서 변경을 하면 다른쪽은 스스로 변경을 안했어도 나중에 값을 꺼내 보면 당연히 바뀌어져 있겠죠^^;(Operations on one can affect another)

 

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

Built-in Data Type

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

정수형

예약어 구조체형식 크기 (Bit) 범위
sbyte System.Sbyte 8 -128~127
byte System.Byte 8 0~255
short System.Int16 16 -32,768~32,767
ushort System.UInt16 16 0~65,535
int System.Int32 32 -2,147,483,648 ~2,147,483,647
uint Systen.UInt32 32 0~4,294,967,295
long System.Int64 64 -(2^63) ~ 2^63-1
ulong System.UInt64 64 0~ 2^64-1

 

실수형, 기타

예약어 구조체형식 크기 (Bit) 범위
실수형
float System.Single 32 1.5x10^-46 ~3.4x10^38
double System.Double 64 5.0x10^-324 ~1.7x10^308
decimal System.Decimal 128 1.0x10^-28 ~7.9x10^28
기타
char System.UInt16 16 유니코드 1 자
bool System.Int32 1 0 또는 1

 

Boolean

boolean type 이 가질 수 있는 값은 true 와 false 입니다. 예 ) bool b = true --> true 는 1 과는 다르며 , 마찬가지로 false 는 0 과는 다릅니다. (C 에서는 TRUE, FALSE 를 #define 을 통해 정의하여 사용 했었습니다.. 정수를 암묵적으로 boolean 형으로 사용한 것이죠.), true 와 false 로 산술 연산을 할 수 없으며 오로지 논리 연산자를 가진 수식에 대해서만 사용가능 합니다.

 

변수 선언 하는 방법

int itemCount;

int itemCount , employeNumber; ( Possible to declare Multiple variables in one)

int employeeNumber; employeeNumber = 23;

int employeeNumber= 23;

또한 Charater형은 다음과 같이 선언 합니다. char middleInitial= ‘J'; C#은 유니코드를 사용하며 char형은 한 문자를 저장하는데 사용 합니다.

Itemcount = Itemcount + 40; --> ItemCount += 40; --> 이건 다아시죠...

 

연산자(Operator)

구분 연산자
기본 연산자 (x), ., f(x), a[x], x++, x--, new, typeof, sizeof, checked, unchecked
단항 연산자 +, -, !, ~, ++x, --x
산술 연산자 +, -, *, /, %
쉬프트 연산자 <<, >>
비교 연산자 <, >, <=, >=, is
비트 연산자 &, ^, |
논리 연산자 &&, ||
조건 연산자 ?:
할당 연산자 =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=

 

[isOperator 예제] is연산자는 런타임시 주어진 타입과 객체가 서로 호환이 되는지를 검사하는 연산자 입니다. 또한 as 연산자는 Type을 변환하는데 변환이 되면 변환 시키고 변환이 안되면 NULL을 돌려 줍니다...(참고하세요~)

//is 연산자 예제
using System;

class isOperator {
static void Main() {
//C#은 모든 타입을 객체로 처리한다.
//System.Int32의 BaseType은 System.ValueType이다.
//System.Object > System.ValueType > System.Int32
int i=0;
object o;
Console.WriteLine("i is int? {0}", i is int);
Console.WriteLine("i is long? {0}", i is long);

if (i is object) {
o = i;
Console.WriteLine("o의 Base Type은 " + o.GetType().BaseType);
}
}
}

 

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

모든 Object(객체)들이 가지는 메소드

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

객체 지향 프로그래밍을 하는것은 객체를 많이 다른다는 이야기 입니다. 이번에는 참고로 모든 객체들이 가지고 있는 기본적인 메소드가 어떤것이 있는지 필요한것만 보도록 하겠습니다. 닷넷에서는 System.Object가 모든 객체의 최상위 클래스 입니다. (물론 자바에선 java.lang.Object 입니다.)

메소드명 설명
bool Equals() 같은 객체인지 비교, 동일한 메모리 공간을 차지해야...
int GetHashCode() 해쉬값을 얻음
Type GetType() Type 에 관한 정보(형식 정보)를 돌려 줍니다.
string ToString() 객체를 대표하는 문자열 반환, 일반적으로 문자열로 변환한다고 보면 됩니다.

 

 

출처 :  http://cafe.naver.com/itclean.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=947