LINQ to Object 마지막입니다.
(사실 내용이 Object에만 해당되는건 아니죠.. -ㅁ-;;)

이번엔 Take와 Skip,그리고 TakeWhile, SkipWhile에 대해볼께요.

예제는 너무나도 간단하네요.


            int[] nums = { 10, 9, 8, 7, 5, 6, 4, 3, 2, 1 };

            var r01 = nums.Take(3);
            var r02 = nums.Skip(3);
            var r03 = nums.TakeWhile(x => x > 5);
            var r04 = nums.SkipWhile(x => x > 5);

간단하지만 (저는)헷깔릴수 있으니 잘 봐야 합니다. ㅋ
일단 nums를 보면 숫자 순서가 7,6,5 가 아니라 7,5,6 입니다.

첫번째로 Take(3)을 하면 그냥 앞에서 3개만 가져옵니다.
두번째로 Skip(3)을 하면 반대로 뒤에서 3개만 가져오죠

While이 좀 헷깔리는데요
r03에서 TakeWhile(x => x > 5)를 하면
x가 5보가 큰 녀석들을 가져오는건데.
이게 (루프를 돌겠죠?) 5보다 큰녀석을 다 가져오는게 아닙니다.
10,9,8,~~ 돌면서 5보다 큰 녀석을 찾는데
보면.. 7 까지는 5보다 크지만 그 다음에 5는 5보다 크지 않죠.
그럼 거기서 끝납니다.
그 다음에 6이라는 숫자가 5보다 크지만.
신경 안써요.
그냥 끝나버리는거에요.

SkipWhile도 비슷해요.
5보다 크면 skip해버리는데
10~7까지 스킵하고. 5부터 출력을 하는데. 그 다음수인 6이 5보다 큰거 따위 신경 안쓰죠.


그럼 이번에는
Non-Generic 타입을 사용하는걸 봐볼께요.
Non-Generic 타입은 바로 사용은 못합니다.

코드를 보면
일단 ArrayList를 선언하고 값을 몇개 넣습니다.
            ArrayList src = new ArrayList();
            for (int i = 0; i < 10; i++)
            {
                src.Add(i + 1);
            }

그 다음에
                      var r01 = from x in src
                      where x > 3
                      select x;


이렇게 해주면 바로 오류가 납니다.
오류 내용은

소스형식 'System.Collections.ArrayList'에 대해 구현된 쿼리 패턴을 찾을 수 없습니다.
'Where'을(를) 찾지 못했습니다. 범위 변수 'x'의 형식을 명시적으로 지정하십시오.

라고 나오네요
ArrayList를 사용하고 싶으면
casting을 해줘야 해요

                      var r01 = from x in src.Cast()
                      where x > 3
                      select x;

요렇게요.
그럼 결과값이 잘 나옵니다.

출처?는 김수영MVP님의 주말특강입니다
by 피요히코~ 2009. 4. 26. 20:16

앞에 포스팅했던 LINQ to Object 이어서 줄줄 입니다.

이번에는 간단하게 SubQuery에 대해 볼께요.
그냥 쿼리 안에 쿼리가 있는건데
T-SQL에서도 조건에 쿼리를 붙이고 하는걸 LINQ로 하면요

           string[] names = { "Tom", "Bill", "Harry", "June", "Mary", "Jay" };

            var r01 = from x in names
                      where x.Length == (
                                          from y in names
                                          orderby y.Length
                                          select y).First().Length
                      select x;

            foreach (var x in r01)
            {
                Console.WriteLine(x);
            }

그냥.
names에서 x라는 녀석을 가져오는데

(여기부터가 subQuery죠)
(다시)
names에서 y라는 녀석을 가져오는데
y의 길이로 정렬을 해서
가져온후에
첫번째 녀석(First())의 길이를 가져온다    << 이녀석이 x의 조건이 되는거에요
(subQuery끝)

이 길이의 x를 가져온다...

가 되는거죠.
정렬에 따로 말이 없으면 ascending이므로
Tom인지  Jay인지는 모르겠지만 암튼 둘중 하나가 First가 되겠죠.
그녀석의 길이와 같은 x를 가져오는것이니

출력값은????
이렇게 나오네요.

이번엔 into에 대해 살펴보죠(헥헥헥)
into키워드는 group, join, select 같은 임시 저장 식별자를 만들어 주는건데요.

예제를 보는게 이해가 빠를꺼에요.

                      var r01 = from x in names
                      where x.Contains("a")
                      select x
                          into subSet
                          where subSet.Length > 4
                          orderby subSet
                          select subSet;


(제가 이해한게 맞다면)
into는 (단어 뜻 그대로)
into키워드 앞의 결과를 뒤에 넣어주는거죠
코드를 보면
x를 subSet에 into했네요.
그 다음에 subSet을 가지고
조건을 걸어서(정렬조건도)
select~

그럼 결과는 어떻게 나올까요?
이름에 "a"가 들어간 놈을 찾아서 나온 결과들중에서(이게 x)
길이가 4 이상인 녀석들을 select하니까.

이렇게 나오네요.
(아마도 x에는 Harry랑 Mary랑 Jay가 있었겠죠)

into를 쓸때 주의할껀
into를 쓴 후에는
원본 x에 접근을 할수가 없다는 거에요.

원본 x에도 접근하고 싶다면
into가 아니라 let을 쓰면 되요
let키워드는 부분결과 집합을 만들어서 쿼리내에서 참조 하는겁니다

                      var r01 = from x in names
                      let temp = x.Replace("a", "")
                      where x.Contains("a")
                      select new
                      {
                          Original = x,
                          Change = temp
                      };

출력값은

간단하네요~

출처?는 김수영MVP님의 주말특강입니다
by 피요히코~ 2009. 4. 26. 19:49

LINQ to Object는

IEnumerable<T> interface가 구현된 어떤 Object에서도 사용이 가능합니다.

Non-Generic 타임은 Cast를 통해 쿼리가 가능합니다.

예제를 보죠.

private static void QuetyTest()
{
     string[] names = { "Tom", "Bill", "Harry", "June", "Mary", "Jay" };

     var r01 = from x in names
          where x.Contains("a")
          orderby x.Length
          select x;

     foreach (var x in r01)
     {
          Console.WriteLine(x);
      }
}

형식은 sql을 해봤다면 눈에 살짝 들어올꺼에요.
3번째 줄에서는 사용할 data를 만들었어요(이름들이죠)

5번째 줄~8번째줄에서 data를 가져오는데요
names는 사용할data
x는 그 data에서 한녀석(?)을 의미해요.
(위의 names에 있는 이름들 하나하나 같은거죠.... 음....)

where 뒤쪽이 이제 가져올 data에 대한 조건을 의미하고
Contains("a")는 "a"가 포함되어 있는지 여부를 확인하는 겁니다.

orderby 는 정렬조건인데
orderby x.Length는 x의 길이로 정렬을 한다는 거죠(참 쉽죠잉~  )

이렇게 하면 r01에 해당 data가 들어가 있겠죠.

그 다음에 출력을 해보면
이렇게 나와요.
(이름에 "a"가 들어가 있는 녀석들만 나오는거죠.)

그럼 이제
앞에 포스팅 했던 글에서 말했던
지연실행에 대해 볼께요.

            var numbers = new List();
            numbers.Add(1);

            var r01 = numbers.Select(x => x * 10);

            numbers.Add(2);

            foreach (var x in r01)
            {
                Console.WriteLine(x);
            }

2번째 줄에서 numbers에 1을 넣고.
3번째 줄에서 numbers.select를 해서 값을 가져옵니다.
가져올 값 x는 x*10을 해서요

그러면 r01에는 10이 들어가겠죠?

그 다음에 numbers에 2를 넣어줍니다.

그리고 출력을 합니다.

결과가 어떻게 나올까요?
10 이 나와야 할꺼 같네요.

근데 10과 20이 출력 됐네요...

10과 20이 출력된 이유는 바로
LINQ가 지연실행되기 때문입니다.
1을 넣고 r01에 1*10을 넣었지만.

그때 쿼리가 실행된게 아니라 데이터가 열거되는 시점인
5번째줄~8번째 줄때 쿼리가 실행됐기 때문에
numbers.Add(2)가 포함된 값이 출력된것이죠.

이걸 잘 염두해 두지 않으면
정말로 원치 않는 엉뚱한 결과가 나올수도 있어요.

하지만 (역시 앞에서 말했던 건데요)
이걸 바로 실행되게 할수도 있어요

var r01 = numbers.Select(x => x * 10).ToList();

이렇게 해주면
바로 쿼리가 실행되서
원하는(이걸 원한다면 말이죠) 값이 출력 되겠죠.

글이 너무 길어지면 보기 싫으니
나머지 예제들은 뒤로 보낼께요

출처?는 김수영MVP님의 주말특강입니다
by 피요히코~ 2009. 4. 26. 19:28

먼저 주요 연산자를 살펴볼께요.

(출처는 김수영님의 주말특강 PPT자료입니다.... )

연산자들이 딱 보면 대충 뭐에 쓰는지 다 감이  오네요.
이 연산자들은
LINQ to Object이건 XML이건 다 적용이 됩니다. 

예제는 다음 LINQ to Object에서 보여드릴께요

LINQ를 사용할때.
꼭 염두해둬야 할께 있는데요
LINQ는 지연실행(Deferred Execution) 된다는 겁니다.

생성시에 쿼리가 실행되는게 아니라 데이터가 열거될때 실행된다는 건데요
이게 왜 중요한지는 뒤의 예제에서 같이 보여드릴꼐요.

단 예외적으로 지연실행 되지 않는 경우가 있는데
- First, Count같은 스칼라 값이나 단일 element를 반환할때
- ToArray, ToList, ToDictionary, ToLookup 실행때 입니다.
(원본 데이터를 처리하는게 아니라. Copy를 할때)

출처?는 김수영MVP님의 주말특강입니다
by 피요히코~ 2009. 4. 26. 19:20
LINQ란 무엇인지 먼저
MSDN의 설명을 간단하게 보면요

업데이트: 2007년 11월

LINQ(통합 언어 쿼리)는 개체와 데이터 간 격차를 줄이므로 Visual Studio 2008 및 .NET Framework 버전 3.5에서 획기적인 혁신입니다.

일반적으로 데이터에 대한 쿼리는 컴파일 시 형식 검사 또는 IntelliSense 지원 없이 단순 문자열로 표현됩니다. 게다가 각 데이터 소스 형식에 대해 SQL 데이터베이스, XML 문서, 다양한 웹 서비스 등 다양한 쿼리 언어를 배워야 합니다. LINQ는 C# 및 Visual Basic에서 쿼리를 고급 언어 구문으로 만듭니다. 언어 키워드 및 친숙한 연산자를 사용하여 개체에 대한 강력한 형식의 컬렉션에 대해 쿼리를 작성합니다. 다음 그림에서는 전체 형식 검사 및 IntelliSense 지원을 사용하여 C#에서 SQL Server 데이터베이스에 대해 부분적으로 완료된 LINQ 쿼리를 보여 줍니다.

Intellisense를 사용한 LINQ 쿼리

Visual Studio에서는 Visual Basic 또는 C#을 사용하여 SQL Server 데이터베이스, XML 문서, ADO.NET 데이터 집합 및 IEnumerable 또는 제네릭 IEnumerable<(Of <(T>)>) 인터페이스를 지원하는 개체의 컬렉션에 대한 LINQ 쿼리를 작성할 수 있습니다. ADO.NET Entity Framework에 대한 LINQ 지원도 계획되어 있으며 여러 웹 서비스 및 다른 데이터베이스 구현에 대한 LINQ 공급자도 타사에 의해 개발되고 있습니다.

새 프로젝트의 LINQ 쿼리나 기존 프로젝트의 LINQ가 아닌 쿼리를 함께 사용할 수 있습니다. 단, 프로젝트에서 .NET Framework 버전 3.5를 대상으로 해야 합니다.

(출처 : MSDN)

이렇게 되어 있네요.
LINQ는 Language 레벨에서 통합된 질의(Query)를 가능케 하는 문법(?) 이라고 하면 되지 않을까 싶어요
(제가 이렇게 알고 있거든요. --ㅋ)

LINQ를 사용하면
코드에서 오류등을 표시해 주기 때문에 오류를 줄일수 있어요.
(그냥 쌩으로 쿼리를 날리면 string으로 넘어가니. 작성 시점에서 이제 맞게 작성 됐는지 알기가 힘들잖아요.
 물론 미리 한번 확인을 해보고 쓰면 되긴 하겠지만요. ㅎㅎ)

LINQ는
LINQ to Object
LINQ to DataSets
LINQ to SQL
LINQ to Entities
LINQ to XML

이 있는데

저는 Object와 DataSet, SQL, XML에 대해 정리해 볼께요.
by 피요히코~ 2009. 4. 26. 19:13
확장메소드에 대해 써볼께요.
MSDN에는 이렇게 나와있다고 하네요

확장 메서드는 형식으 ㅣ인스턴스 메서드인 것처럼 호출할수 있도록 형식과 연결된 수 있는
정적 메서드 입니다.
이 기능을 사용하면 실제로 기존 형식을 수정하지 않고도 기존 형ㅅ익에 새 메서드를 추가할수 있습니다.

Javascript에서도 이런 기능이 있죠.(Prototype)

C#에서는 IEnumerable<T> interface가 구현된 모든 타입에서 구현이 가능합니다.

간단한 소스를 봐보면요
    public static class MyExtensions
    {
        public static int wordCount(this string str)
        {
            return str.Length;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string s = "Extension Methods";
            Console.WriteLine(s.wordCount().ToString());
        }
    }

 

확장메서드의 가장 큰 장점(?) 은 원래 부터 정의되어 있는 메서드 처럼 사용할수 있다는거죠.
실제로 String에는 wordCount() 라는 메서드가 없잖아요.
근데 그냥 . 찍고 wordCount() 해주면 새로 정의한 메서드가 호출되는거죠.
(사용자가 사용하기가 참 편하겠죠)
차이가 있다면 인텔리센스에서 메서드표시 옆에 화살표가 표시되는것과
이름옆에 (확장)이라고 표시되는거죠.



라인1 부터 7 까지가 확장메서드 입니다.
간단하게 string값의 길이(length)를 반환하는 메서드를 작성했어요(출력값은 17 이에요)

MyExtentions 라는 정적 클래스를 선언하고 그 안에 wordCount라는 메서드를 선언했어요.
인수는 string 객체이며 this 키워드를 붙입니다.
여기서 this는 호출객체를 의미하는 참조자가 아니라 뒤의 클래스에 대한 확장메서드임을 의미하는
지정자에요.  wordCount가 string의 확장메서드라는 의미죠.

코드에서는 인수를 한개만 받았지만 실제로 인수는 제한이 없습니다.
두번째 인수부터는 실제 연산에 필요한 값들을 받으면 되는거죠.

(아무 의미가 없지만. --)string의 length에 특정 숫자를 붙인 int를 받는 메서드를 작성하고 싶으면


     public static class MyExtensions
    {
        public static int wordCount(this string str, int add)
        {
            return str.Length+add;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string s = "Extension Methods";
            Console.WriteLine(s.wordCount(5).ToString());
        }
    }


이렇게 해주면 되죠.(출력값은 17+5 해서 22가 나오겠죠?)

확장메서드는 인스턴스 메서드처럼 사용되지만 소속은 분명히 클래스 외부입니다.
그러므로(당연히) 확장하는 클래스의 숨겨진 멤버들에는 접근을 할수가 없어요.
그래서 확장 메서드로 클래스를 확장한다고 캡슐화를 위한바는것도 아니고.
보안상으로도 별 문제가 없다고 하네요.

by 피요히코~ 2009. 4. 26. 18:45
이번엔 익명형식이라는 녀석에 대해 알아볼께요.

익명형식은 이렇게 사용해요.

var anonyValue = new {Name = "피요히코", Age=30 };

아주 간단하죠?
이렇게 하면 내부적으로
이렇게 바꿔준다네요


internal class???
{
     string _Name;
     int _Age;
     public string Name
     {
          get{return _Name;} set {_Name = value;}
     }
     public int Age
     {
          get{return _Age;} set{_Age = value;}
     }
}

알아서 해주는거죠.
대신 이렇게 알아서 하기 위해서
compile시에는 느려지게 됩니다.
(complie때 알아서 알아서 하려면 어쩔수 었겠죠)

대신 컴파일 되고 나서는 성능에 대한 문제는 없다네요

이런 익명형식은
- 이름을 컨트롤 할수가 없어요. (complie시에 알아서 알아서)
- 항상 System.Object를 확장해요
- 필드와 프로퍼티는 항상 read-only에요
- 이벤트나 커스텀메소드등을 지원안해요.
- 항상 묵시적으로 selead에요(상속같은건 못해요)
- 항상 기본생성자를 사용해서 생성되요.


출처?는 김수영MVP님의 주말특강입니다
by 피요히코~ 2009. 4. 26. 13:56

토요일에 있었던 김수영MVP님의 교육을 다녀온 후에
좋은 내용을 너무 많이 듣고 와서
정리의 필요성을 느끼고 정리합니다. ㅋ
(수영님 다시한번 감사~ )

C# 3.0에서 새로 생긴 타입(?) 인 var는 Javascript에서 많이 보던 녀석이죠.
int나 string처럼 변수에 들어가는 녀석들의 종류가 미리 명시되는게 아니라
변수에 값이 대입되고 나서야 타입이 정해지는(맞죠? ;;;)
여러면서에 C#의 Object타입과도 비슷하지만.
다른녀석이죠

C#의 Object와 비교해 본다면
Object타입은 .NET에서의 모든 자료형은 Object를 상속받기 때문에
어떤형식도 Object에 넣을수는 있지만. Object는 타입을 추정할수가 없지요

예를들어서 제가

object objType = "초기화";
var varType = "초기화";

이런 코드를 작성했다고 할때

이 변수를 가지고 뭔가를 하려고 할때 . 을 찍어보면 차이가 확 나타나요




var 타입의 경우는
'이녀석이 string이구만~ ' 이라고 타입을 추정해서 인텔리센스세 string이 지원하는 메소드등등이 줄줄 보이는데요
object의 경우는 그렇지 않죠.
아주아주아주 기본적인 (이게 Object형식이면 모두 지원되는 메소드 겠죠?) 메소드 딸랑 4개만 보이네요.

또 다른 차이는
var타입의 경우는 Compile 때 타입을 검사하고 Object는 Runtime시에 검사를 한다는 겁니다.
이말은
var타입의 경우는 compile시에 타입이 확정되기 때문에
불필요한 boxing 이나 unboxing등이 생기지 않는다는거죠
compile때 이미
'이녀석은 int구나..'
혹은
'이녀석은 string이구나' 등이 정해지니
그럴일이 없겠죠.

또한 compile시에 타입을 검사하고 확정하기 떄문에 타입이 변경될수 없어요.
처음에 var타입에 숫자를 넣었다면 앞으로 그 변수에는 숫자만 넣어야 한다는거죠.

출처?는 김수영MVP님의 주말특강입니다
by 피요히코~ 2009. 4. 26. 13:42
영어를 잘 못해서 그런건지.. (잘 해도 어려울꺼 같은)
메니페스트는.. 일단 말부터 너무 어려운거 같아요..

일단 메니페스트가 뭔지. (더불어 어셈블리가 뭔지 한번 정리를 해보죠... 제가 잘 몰라서.. )




네이뇬이 이렇게 가르쳐 주네요...
하지만 제가 원하는 대답은 아니네요..

이제 곧 영국으로 가버리는(이제 얼굴좀 익혔는데. ㅠ) 경훈씨가 HOONS에 올린 글을 보면..


.NET Assembly

닷넷을 어느정도 공부해본 사람들은 어셈블리(assembly)에 대한 말을 많이 듣게 되는데, 닷넷 어셈블리가 무엇인지, 어떻게 사용하는 것인지 한번 생각해 보도록 합시다.

 

어셈블리란 무엇인가

1. 어셈블리는 코드들의 논리적인 묶음이다.

2. 어셈블리는 물리적으로 DLL또는 EXE로 존재한다.

3. 한 개의 어셈블리는 한 개이상의 파일을 포함할 수 있다.

4. 어셈블리안에는 어떤 형태의 파일도 포함될 수 있다(예: 텍스트 파일, 이미지파일등)

5. 작성된 소스코드가 어셈블리로 묶여지지 않다면, 다른 어플리케이션에서는 이용할 수가 없다.

6. 어셈블리파일엔 자체정보를 가지고 있는데 이를 어셈블리 메니페스트(Manifest)라 한다.

 

어셈블리 메니페스트(manifest) 대해

1. 어셈블리 메니페스트는 해당 어셈블리의 정보들을 저장하고 있는 데이터 구조(data structure)이다.

2. 이러한 정보는 어셈블리 파일(DLL/EXE) 자체에 포함되어 있다.

3. 메니페스트는 버전정보나, 구성된 파일의 리스트등을 포함하고 있다.

 

Private assembly VS Shared assemly

단일 어플리케이션에만 사용되는 어셈블리를 private assembly라 한다. 예를 들어서, 여러분이 업무로직을 가지고 있는 DLL을 하나 만들었다면, 그리고 DLL을 사용하는 클라이언트 어플리케이션이 오직 한 개이라면, 그것은 대부분 private assembly인 것이다. 이 때 프로그램이 제대로 동작되기 위해서는 프로그램이 설치된 같은 폴더에 DLL이 존재해야만 한다. 

이와 반대로, 만약 하나의 DLL을 만들고 나서 이를 여러 어플리케이션에서 사용하도록 만들었다면, 각 어플리케이션의 해당 폴더마다 복사본이 존재하는 것이 아니라, DLL을 Global Assembly Cache에 위치시켜야만 한다. 이러한 어셈블리를 shared assembly라 한다.

 

Global Assembly Cache ?

GAC(Global Assembly Cache)는 모든 shared assembly가 저장되는 특정 폴더일 뿐이다.

이 폴더의 위치는 <드라이브명>:/winnt/assembly 이다. 실제 이 폴더에 들어가보면, 많은 전역 어셈블리들을 볼 수 있다.

 

어셈블리는 DLL 지옥을 해결하였다는데

앞에서 언급했듯이 직접 작성한 대부분의 어셈블리는 private이다. 그러므로 각 어플리케이션은 자체적으로 설치된 폴더에 있는 어셈블리를 참조한다. Private형식에서는 같은 이름의 여러버전이 있다하더라도 충돌을 피할 수 있다.

이해를 돕기위해 한가지 예를 들어본다.

1. Assembly1이라는 이름의 어셈블리를 제작한다.

2. Assembly1을 이용하는 Client1이라는 어플리케이션을 만든다.

3. 클라이언트 프로그램을 c:\MyApp1이라는 폴더에 설치하고, Assembly1도 이 폴더에 설치한다.

4. 며칠이 지난 후에 Assembly1이 수정이 되었다고 가정한다.

5. 수정된 Assembly1을 이용한 클라이언트 어플리케이션(Client2)를 제작한다.

6. 이 클라이언트 프로그램을 c:\MyApp2라는 폴더에 설치하고 Assembly1도 이 폴더에 설치한다.

7. 각각의 프로그램은 같은 이름의 Assembly1이라는 어셈블리를 사용하고 있지만, 버전은 서로 다른 것이며, 아무 문제없이 충돌없이 동작된다.

 

여기까지는 Private Assembly의 예를 든것이다. 이처럼 어셈블리는 각각의 폴더에 설치되어 있기 때문에 직접 변경이 되지 않는 한 버전변경에 영향을 받지 않는다고 할 수 있다. 그럼 이번에는 Shared 어셈블리에 대해 알아보겠다. 이 경우에서는 버전이 매우 중요하다. 버전번호는 다음과 같은 형태로 생성된다.

major.mino,build.revision

만약 어셈블리에 변경을 가했을 경우, major, minor버전이 같다면 변경된 어셈블리는 기존 것과 호환된다고 할 수 있다. 만약 클라이언트 프로그램에서 어셈블리의 사용을 요청하게 되면, major,minor버전이 맞는 것중에서 가장 최근의 build와 revision을 갖는 어셈블리가 제공된다.

 

Shared Aassembly 만드는 

1. DLL/EXE를 제작할 소스코드를 준비한다.

2. SN 유틸리티를 이용하여 유니크(unique)한 어셈블리명을 생성한다.

3. AssemblyInfo 파일을 수정하여 private key를 서명한다.

4. DLL/EXE를 컴파일한다.

5. 생성된 DLL/EXE를 GACUTIL 유틸리티를 이용하여 global assembly cache에 위치시킨다.

이렇게만 하면, shared 어셈블리가 작성이 된다. 그러면 한가지씩 자세하게 알아보도록 하자.

 

Unique Assembly Name 생성법

마이크로 소프트에서는 어셈블리의 유일성을 보장하기 위해서 public-private key(공개키/개인키)기반의 로직을 이용한다. 이 공개키/개인키의 짝(pair)은 SN.EXE 라는 유틸리티를 이용해서 생성한다.(SN은 shared name의 의미를 갖고있다) 여러가지 다양한 옵션이 있지만, 일반적인 syntax는 다음과 같다.

sn -k 생성될 파일명

k는 키(key)를 생성하겠다는 의미이며, 이를 실행하면 파일이 하나 생성된다.

 

전자서명

어셈블리를 shared cache에 위치시키기 위해서는, sn유틸리티를 이용해서 만든 키를 이용하여 서명을 해야한다. 이 때 서명에 관련한 정보들을 담는 특별한 파일이 AssemblyInfo파일이다. AssemblyInfo 파일에 다음을 추가한다.

<Assembly: Assemblykeyfile("파일명")>

 

Global Assembly Cache에 등록하기

GACUTIL /i my_dll.dll

이렇다고 하네요. 아주 깔끔하게 정리가 잘 되어있네요. ㅎㅎ
(원본은 개발자가 알아두면 좋은 ASP.NET 지식 (어셈블리) 405 0 minotech@join )

자 그러면 어셈블리의 메니페스트에 저장되는 정보에는 어떤것이 있는지 보죠..

Assembly name : 어셈블리의 이름을 나타냅니다.

Versioning information :  이녀석은 4개의 부분으로 되어있고, 버전넘버가 저장되어 있습니다. 개정및 빌드넘버/ major 버전넘버와 minor 버전넘버도 포함되어 있어요

An (optional) shared name and signed assembly hash : 여긴 어셈블리 배포정보가 있어요.

Files : 어셈블리에 있는 모든 파일의 목록이 있습니다.

Referenced assemblies : 메니페스트의 어셈블리에서 직접 참조하는 모든 외부 어셈블리 목록이 있습니다.

Types : 타입이 저장되어있는 모듈과 매핑된 어셈블리의 모든 타입에 대한 목록이 포함되 있습니다. 
         
Security permissions : 어셈블리에서 명시적으로 거부된 보안사용권한(permission)의 목록입니다

Custom attributes : 타입에 따라 사용자정의(custom) 어트리뷰트는 리플렉션시 빠르게 접근하기 위해서 어셈블리의 메니페스트에 저장됩니다.

Product information Company, Trademark, Product, Copyright 값도 저장되어 있습니다




짧은 지식으로 지금 일을 하고 있지만
역시나 알아야 할것(인지는 모르겠지만ㅎㅎ)이 참 많네요.
부지런해야 겠습니다.

by 피요히코~ 2009. 4. 24. 00:34
아주 간단한 소스코드를 빌드를 하고
IL DASM로 불러들였습니다.

namespace insideCSharp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("OTZ");
        }
    }
}


정말 간단한 소스네요....

이걸 IL DASM으로 불러들이면


이렇게 보입니다.
여기서 두번째 줄에 있는 MANIFEST를 더블클릭하면 어셈블리 정보를 설명하는
메타데이터 정보를 볼수가 있어요

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 2:0:0:0
}
.assembly insideCSharp
{
  .custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0C 69 6E 73 69 64 65 43 53 68 61 72 70 00   // ...insideCSharp.
                                                                                              00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 0C 42 6C 61 63 6B 45 64 69 74 69 6F 6E 00   // ...BlackEdition.
                                                                                                00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 0C 69 6E 73 69 64 65 43 53 68 61 72 70 00   // ...insideCSharp.
                                                                                                00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 1E 43 6F 70 79 72 69 67 68 74 20 C2 A9 20   // ...Copyright ..
                                                                                                  42 6C 61 63 6B 45 64 69 74 69 6F 6E 20 32 30 30   // BlackEdition 200
                                                                                                  39 00 00 )                                        // 9..
  .custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 64 63 37 31 35 34 62 61 2D 30 30 65 34   // ..$dc7154ba-00e4
                                                                                                  2D 34 33 62 31 2D 61 30 30 61 2D 34 36 62 32 61   // -43b1-a00a-46b2a
                                                                                                  35 62 37 64 32 33 36 00 00 )                      // 5b7d236..
  .custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 )             // ...1.0.0.0..

  // --- 다음 사용자 지정 특성이 자동으로 추가됩니다. 주석 처리를 제거하지 마십시오. -------
  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )

  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
  .hash algorithm 0x00008004
  .ver 1:0:0:0
}
.module insideCSharp.exe
// MVID: {8A57E23A-CCB3-4592-9075-A79E5D701B7F}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x03F60000

참 기네요..
이걸 처음봤을때는(지금도 물론) 눈앞이 캄캄하네요....
가뜩이나 가로로 쭉쭉 늘어선 글을 붙여넣으니 당췌 뭐가뭔지 모르겠네요...

여기서 첫번째 블럭은 외부어셈블리를 참조하는데 사용되는 .assembly 레코드입니다.

어셈블리의 가장 큰 장점중 하나는 버전관리가 가능하다는 것... 이라고 하는데요. 아직 저에게는 그다지 와닿지 않는 내용입니다. --ㅋ
제가 컴파일한 insideCSharp  어셈블리는 mscorlib 어셈블리의 2.0.0.0 버전을 사용하고 있다네요.

두번째 블럭은 이 어셈블리에 대한 정보를 포함하고 있습니다.
책에서 본 바로는 명시적으로 빌드 프로세스중에 버전 넘버를 지정하지 않으면 0.0.0.0 이라고 하는데
왜 저는 1.0.0.0 인걸까요.........

책이 version 2003이니.. 바뀐걸수도 있겠고. 제가 모르는 무언가가 있는지도 모르겠네요... ㅠ
위에 노란블럭안을 보면 몇가지 어트리뷰트가 나와 있는데요.
위의 어트리뷰트에 대한 내용들은 공부가 더 진행된후에 다시 언급하도록 할께요.
(그나저나 책에서는 Debug쪽 어트리뷰트만 나오더니. 제꺼에서는 상당히 많은 어트리뷰트가 보이는군요....
 책과 다르면 매우 난감한데요....)

다음으로는 클래스의 생성자를 볼께요. (6번째줄의 .ctor : void() 를 더블클릭하면 나와요)

.method public hidebysig specialname rtspecialname
        instance void  .ctor() cil managed
{
  // 코드 크기       7 (0x7)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  ret
} // end of method Program::.ctor

첫째줄에서 두번째줄까지는 단순히 메소드가 public이고, specialname, rtspecialname 어트리뷰트의 특징을 나타냅니다.
이러한 특정 메서드에 대한 코드는 CLI(Common Language Infrastructure)에 대한 의미를 가지고 있다고 하네요.
cil managed 어트리뷰트는 managed 메서드라는 걸 의미합니다.

메소드는 처음으로 Idarg라는 opcode를 통해 인자를 스택으로 로드합니다.
Idarg 다음의 '0'은 첫번째 인수를 뜻합니다.
두번째 call 이라는 opcode는 System.Object를 호출하는데 사용됩니다.
마지막 ret opcode는 단순히 호출메소드로 컨트롤을 반환한다고 하네요.
(코드는 쉬운데. 이놈은 어렵네요....)

이번에는 Main 메소드가 어떻게 생겼는지 볼죠..

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // 코드 크기       13 (0xd)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "OTZ"
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  ret
} // end of method Program::Main
위에서 한번 보고 나니.
조금 눈에 들어오네요

하지만 책과 또 다른!!!!
IL_0000과 000b의 nop은 뭐하는 녀석일까요...

나머지 녀석들은 위랑 비슷한데 말이죠..
Idstr은 문자열 OTZ를 스택에올려주고.
call을 사용해서 System.Console::WriteLine을 불러냅니다.

문자로된 문자열을 넘겨도. 이 값은 실제로는 System.String 클래스의 인스턴스입니다.(문자니깐요)



IL DASM으로 내부정보를 보면
개발자가 알아야할 지식을 갖추는데도 도움이 되고
개발 생산성도 높일수 있을것이라고 하니(책에서... 실제로는 어떨지 아직 모르겠군요.. 도움이 되긴 하겠죠..)
앞으로 이 녀석과 친해질수 있도록 많이 노력해야 겠네요..
by 피요히코~ 2009. 4. 24. 00:17
| 1 2 3 4 5 6 7 8 ··· 11 |