프로그래밍에 있어 언어적 특성을 이해하는 것도 중요하지만 무엇보다도 먼저 눈앞의 문제를 해겨 하기 위해 그 언어에서 제공하는 함수 즉 레퍼런스를 빨리 찾아서 사용하는 것이 중요하다. 시간적이 여유가 있다면 직접 비슷한 기능을 만들어 보는것도 좋겠지만 프로그램의 일관성을 유지하고 빠른 개발을 하기 위해선 그 언어에서 제공하는 레퍼런스를 잘 쓰는 것 보다 좋은 방법은 없다고 생각한다.

사실 어지간한 실력자라 아니라면 그 언어에서 제공하는 함수보다 나은 함수를 만들기는 쉽지 않을것이다. 더군나다 이미 있는 기능을 궂이 새로 만들 필요가 있을까??

소개하려는 내용도 짧은데 서두가 너무 길어지는 것 같군-_-;

우선 자바를 주로 해왔던 관계로 또 자바를 언급한다. C# 메서드를 소개하는데 자바 메서드를 언급하다니… 조금 우습지만 사실 프로그래밍을 조금 해본사람이라면 알겠지만 모든 언어가 제공하는 클래스의 함수가 이름만 다를뿐이지 죄다 비슷비슷하다. 그러니 한 언어만 잘 알아도 다른 언어를 쉽게 이해 할 수 있다는 이유도 여기에 있다. 아예 새로운 기능을 만들어 내는 연구개발자가 아닌이상 적당히 논리적인 생각을 갖고 API잘 쓰면 어느정도 프로그램을 만들수 있을 테니 말이다.

오늘 소개하려는 클래스는 배열클래스이다.
자바에서는 Java.Util 에서 Set, Map, List 클래스로 제공하고 있으며, C#에서는 System.Collections에서 Set, Table, List로 제공하고 있다.(참고: 자바에서는 HashTable클래스도 제공되고 있지만 HashMap이 동일한 기능을 하기 때문에 HashMap으로 언급했음)

Set, Table, List라고 말하니 조금 어리둥절할 사람이 있겠지만 이건 기본적인 이름이다. 이 구조를 잘 이해하면 클래스이 본연 기능을 바로 이해 할 수 있다.

Set이란 이름의 HashSet은 중복을 허용하지 않는 배열 클래스이다.
Map/Table이란 이름의 HashMap/HashTable은 키와 값을 매칭하는 배열 클래스이다.
List란 이름의 ArrayList는 중복을 허용하는 배열 클래스이다.

여기서 C#은 System.Collections.Generic 밑에 HashSet을 관리하는데 이는 Generics라는 기능을 사용하기 때문이다. 참고로 System.Collections밑에 있는 HashTable은 System.Collections.Generic밑에 Dictionary가 동일한 기능을 제공하고 있다.

Generic에 관련된 자세한 내용은 검색을 참고하기 바라며 간략히 언급하자면
HashSet <string>hs = new HashSet<string>(); 과 같이 사용할 데이터의 타입을 미리 정해놓고 컴파일할 때 구조를 정의하는 기능을 말한다.

앞서 소개한 내용이 복잡하고 어려웠다면 아래 소스를 보고 이해하기 바란다.

만약 중복데이터를 허용하는 배열을 사용한다면?
ArrayList arrData = new ArrayList();
arrData.add(“1”);
arrData.add(“1”);
arrData.add(“2”);
arrData.add(“2”);

출력:
1,1,2,2

HashSet <string>hs = new HashSet<string>();
Hs.add(“1”);
Hs.add(“1”);
Hs.add(“2”);
Hs.add(“2”);

출력:
1,2

이처럼 출력된다.

Posted by Jake Kim

C# 3.0이 제공하는 새로운 기술이 참 많은데 그 중 가장 많이 거론 되는 내용이 LINQ기술일 것이다. 하지만 LINQ보다 도 코딩 시 더 유용한 기술이 있어 소개해보려 합니다.

Extension Method

구글에서 “Extension Method” 이라고 검색해보면 꽤나 많은 글들이 올라오고 사용방법에 대해서 자세히 설명하고 있으니 관련 글을 찾아봐도 되겠지만 간략히 이해 하고 싶은 분들은 아래 글을 참고해주세요. 제가 쓰는 글보다는 구글에 올라온 글이 백번 낫겠지만^^;

Extension Method
는 말 그대로 메서드를 확장해서 사용하는 기술입니다. 예제를 보면서 설명 하도록 하겠습니다.



소개하려는 메서드는 문자를 숫자로 바꿔주는 소스입니다. 함수를 바로 사용하기 위해서 static을 많이 사용합니다. 그리고 위의 소스처럼 함수 인자에 뭔가를 넣겠죠.

int j = EMClass.ToInt32Static(s);    // 일반 적으로 사용하는 방법

이렇게 말입니다.

 

일단 static을 사용했으니 인스턴스 객체를 만들지 않고 바로 메서드를 사용할 수 있으니 간단하죠. 그런데 그 아래 확장 메서드라는 라인을 보면 string 클래스에 ToInt32Ext()메서드가 있는것처럼 바로 접근해서 사용하는 것을 볼 수 있습니다. 최소한 가독성이나 사용 면에서는 확장 메서드가 사용상 용이해 보입니다.


딱히 필요성을 모르겠다는 분들을 위해 다른 소스를 예제로 보여드리겠습니다.

우선 오늘 날짜에서 특정 일을 빼주는 함수를 만든다고 가정 하겠습니다.

그럼 보통 이런 함수를 구상 하시리라 예상됩니다.

 

public static DateTime MinusDay(DateTime dt, int days)

{

DateTime d = dt.AddDays(-days);

return d;

}

 

날짜 파라메터, 지정 날짜 파라메터 그리고 아래 처럼 사용할 것입니다.

 

DateTime current = DateTime.Now;

DateTime dt1 = DateTimerHelper.MinusDay(current, 3);

 

하지만 확장 메서드를 사용하면 마치 DateTime MinusDay라는 메서드가 있는 것 처럼 사용할 수 있습니다.

 

public static DateTime EX_MinusDay(this DateTime dt, int days)

{

    DateTime d = dt.AddDays(-days);

    return d;

}
 

DateTime dt2 = current.EX_MinusDay(3);

소스입니다.



확장 메서드(Extension Method)를 사용하기 위해서는 몇가지 조건이 필요합니다. 확장 메서드는 static class에 static method로 선언 하여, instance메소드를 호출 하듯이 사용하면 됩니다.


참고:
http://www.developer.com/net/csharp/article.php/3592216
http://www.taeyo.net/Columns/View.aspx?SEQ=312&PSEQ=11

Posted by Jake Kim

구분: 엑셀
설명: 각 필드의 값을 비교하여 특정 값을 복사하기

엑셀을 사용 하다 보면 두 필드의 값을 비교하여 그 값이 일치 한다면 특정 필드의 값을 복사해 올 일이 종종 있다. 이럴 때 사용할 수 있는 유용한 엑셀 함수가 VLOOKUP이다.

VLOOKUP의 함수 인자를 살표보면 VLOOKUP(LOOKUP_VALUE, Table_array, Col_index_num,Range_lookup) 이와 같다.

Lookup_value: 비교값
Table_array: 찾을 대상 목록
Col_index_num: 찾을 대상 목록에서 복사해올 인덱스
Range_lookup: 정확도

함수에 관한 세부 설명은 엑셀에서 직접 참고 하기 바라며, VLOOKUP을 통해 어떻게 일을 편하게 할 수 있는지 알아보자.



A데이터와 B데이터의 코드명을 비교하여 2자리가 같으면 대분류, 3자리가 같으면 중분류, 5자리가 같으면 소분류로 나누려고 한다.

이때 비교 대상의 코드명을 2자리,3자리, 5자리로 분류하고 이 값을 VLOOKUP을 사용하여 비교하면 간단히 해결 할 수 있다.

1.먼저 코드명 나누기는 자리수로 =LEFT(대상,자리수)로 D번과 같이 나눈다.
2.=VLOOKUP을 사용하여 나눠진 코드명을 비교대상 테이블에서 찾는다.

=VLOOKUP(J2, $A:$B,2,FALSE): 비교값, 대상테이블, 대상테이블의 복사위치, 정확도
이때 중요한 것은 대상 즉 J2는 드래그할 때 마다 셀위치가 바껴야 하고 대상 테이블은 그대로 있어야 한다. 이따 대상테이블의 주소를 고정으로 둘 수 있는데 셀주소 앞에 $를 붙이면 된다.
 

Posted by Jake Kim

예제문과 기술내용은 해석보다는 바로 보시고 이해할 만한 수준이기에 구조체에 관한 몇 줄만 번역 했습니다.

구조체를 사용하는 이유로 프로그램의 성능 향상과 깔끔한 코드를 원하기 때문일 것이다. 뿐만 아니라 구조체는 일부 상황에서 클래스 보다 나은 혜택을 제공한다. 물론 여기에는 문제점도 있지만 클래스와 구조체를 잘 혼합하여 사용한다면 개발 시간 단축과 프로그램 효율에 도움이 될 것이다.

여기 몇 가지 예제들과 함께 벤치마킹 데이터가 있으니 참고하기 바란다.

C#에서의 구조체란?
우선 구조체란 각각의 필드에 동일하게 사용자가 원하는 타입의 값을 저장 할 수 있도록 만들어 준다. 이때 데이터의 참조로 저장되는 것이 아니라 문자열 안의 문자배열과 동일한 형태로 저장된다.

MSDN에 의하면 구조체는 힙 얼로케이션이션(할당)을 요구하지 않는다고 한다. 이 말은 클래스 타입의 변수가 데이터를 참조하는데 반해 구조체 타입의 값들은 곧바로 데이터 구조를 포함한다는 것이다. 즉 구조체를 통해 C#에서 객체가 넘치는 것을 피할 수 있다.

(이 부분의 번역이 매끄럽지 않다. 추가 설명 하자면, 클래스는 인스턴스를 만들어 그 객체를 참조하도록 만드는데 이때 힙 부분에 그 참조 되는 부분이 올라가고 일정부부 사용이 되지 않을 때 가비지컬렉터에 의해 제거 되는데, 가비지컬렉터 사용은 결국 성능에 도움이 되지 않기 때문에 구조체를 통해 그 클래스 객체 생성을 막을 수 있고 성능에 도움이 된다는 뜻으로 해석 된다.)

아래 글 주소: http://dotnetperls.com/Content/Struct-Examples.aspx

Problem
. You want to use structs to improve the performance and clarity of your code. Structs have benefits over classes in some situations, but also negatives. Solution. I have prepared examples and benchmarks here.

1. What structs are in C#
Structs are custom value types that store the values in each field together. They do not store referenced data, such as the character array in a string.

What MSDN says is that structs "do not require heap allocation." It says that variables of struct type "directly contain the data of the struct, whereas a variable of a class type contains a reference to the data." [MSDN source]

What that means is that with structs you avoid the overhead of objects in C#. You can combine multiple fields, reducing memory pressure and improving performance.

Value semantics: this term indicates whether the variable is being used like numbers and values are, or as an inherited class. "Complex numbers, points in a coordinate system, or key-value pairs in a dictionary" are included.

2. Using a struct and debugging it
This example console program uses a struct called Simple, which stores three values itself: two numbers and a boolean.

class Program
{
    struct Simple
    {
        public int Position;
        public bool Exists;
        public double LastValue;
    };

    static void Main()
    {
        Simple s;
        s.Position = 1;
        s.Exists = false;
        s.LastValue = 5.5;
    }
}

As an aside,
there are practical uses to structs and they are an important part of the language. Here's what the Visual Studio debugger shows inside the struct. Note that the struct is the type "Program.Simple".



3. When you should choose a struct
First, only consider structs in performance-sensitive parts of your program. Points containing coordinates and positions are excellent examples of structs, as is the DateTime struct.

Many times in programs you have small classes that really serve as collections of related variables you store in memory. You don't have inheritance or polymorphism. These often make ideal structs.

●Use structs for offsets.
Structs are useful for storing coordinates of offsets in your files. These usually contain integers.
●Use structs for graphics.
When using graphics contexts, use structs for points and coordinates.
●Use structs with databases.
MSDN provides an example of a nullable integer used for databases. If you don't want to use Nullable<T>, use this. [Database Integer Type: http://msdn.microsoft.com/en-us/library/aa664482(VS.71).aspx]

4. Use property accessors with structs
Remember that your struct cannot inherit like classes or have complex constructors. However, you can provide properties for it that simplify access to its data.

using System;

class Program
{
    static void Main()
    {
        // Initialize to 0.
        S st = new S();
        st.X = 5;
        Console.WriteLine(st.X);
        // 5
    }

    struct S
    {
        int _x;
        public int X
        {
            get { return _x; }
            set
            {
                if (value < 10)
                {
                    _x = value;
                }
            }
        }
    };
}

5. Stack versus heap allocation

Local value types are allocated on the stack. This includes integers such as "int i" for loops. When you create an object from a class in a function, it is allocated on the heap.

The stack is much faster normally. The details of stacks and heaps are out of the scope here, but are worthwhile studying.

6. Changing your class to a struct
First, you can't easily change classes that inherit or implement interfaces to structs. You cannot use a custom default constructor on structs, as when they are constructed, all fields are assigned to 0. [Structs in C#: http://www.codeproject.com/KB/cs/structs_in_csharp.aspx]


 Class version  Struct version

 class Program
{
    class C
    {
        public int X;
        public int Y;
    };

    static void Main()
    {
        C local = new C();
        local.X = 1;
        local.Y = 2;
    }
}

 class Program
{
    struct C
    {
        public int X;
        public int Y;
    };

    static void Main()
    {
        C local;
        local.X = 1;
        local.Y = 2;
    }
}


Struct usage tip: You don't have to instantiate your struct with the new keyword. It works like an int, instead, which means you can access it directly without allocating it explicitly.

7. Can I compare my struct against null?
No. You should think of structs as ints or bools. You can't set your integer variable to null. Nullable types, however, are a generic type that you can use with databases and declare null ints. [Nullable Types - MSDN: http://msdn.microsoft.com/en-us/library/1t3y8s4s(VS.80).aspx]

Interestingly, nullable types themselves (System.Nullable) are implemented with structs. The link to Database Integer Type is similar.

8. Memory benchmarks of structs
I looked at the memory layout of the console program in the CLRProfiler. This is a free tool by Microsoft that visualizes the memory allocations of .NET programs.

The first picture here is the memory profile of the version that uses classes. It indicates that the List took 512 KB and was 1 object, and internally it stored 100000 objects and took 3.8 MB.



Using structs, CLRProfiler indicates that the List took 24 bytes and contained 1 object of 4.0 MB. That 1 object is an array of 100000 structures, all stored together.



 Version  Size of List<> Size of internal array 
 Class 1 object
512 KB
100000 objects
3.8 MB
 Struct 1 object
24 bytes
1 object
4.0 MB


What this means is that structs are not stored as separate objects in arrays, but are grouped together. This is possible because they are value types. We see that structs consume less memory.

9. Allocation benchmarks for structs
It was easier to gather speed benchmarks of structs. I compared two classes to two structs. Both pairs of opposites use either 8 ints or 4 strings.

 Classes tested  Structs tested
 class S
{
    public int A;
    public int B;
    public int C;
    public int D;
    public int E;
    public int F;
    public int G;
    public int H;
};
struct S
{
    public int A;
    public int B;
    public int C;
    public int D;
    public int E;
    public int F;
    public int G;
    public int H;
};
class S
{
    public string A;
    public string B;
    public string C;
    public string D;
}
struct S
{
    public string A;
    public string B;
    public string C;
    public string D;
}


Recall that because strings are reference types, their internal data is not embedded in the struct. Just the reference or pointer is.

I make note here that the performance benefits of structs with strings persists even when their referential data is accessed, as by assignment or appending.



We see substantial speedups of over two times when allocating the structs. This is because they are value types allocated on the stack. Note they are stored in a List field.

Specific notes: I tried to ensure accuracy of the test by assigning each field and avoiding property accesses, which is why I use public fields.

10. Should I use strings in structs?
Yes, as it can improve performance. However, the struct will not store the string's data. That will be stored externally, where the reference points.

However, using structs can improve performance with the string reference itself. Remember that references are also data that need to be allocated, which we can use struct for.

11. Use struct for ASP.NET website
In my web project, I record thousands of referrer data objects. These store two string fields and a DateTime field. By hovering over DateTime in Visual Studio, you see that it too is a struct.

Because DateTime itself is a struct, it will be stored directly in the struct allocation on the stack. Thus, in a struct with two strings and a DateTime, the struct will hold two references and one value together.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var _d = new Dictionary<string, ReferrerInfo>();

        // New struct:
        ReferrerInfo i;
        i.OriginalString = "cat";
        i.Target = "mat";
        i.Time = DateTime.Now;

        _d.Add("info", i);
    }

    /// <summary>
    /// Contains information about referrers.
    /// </summary>
    struct ReferrerInfo
    {
        public string OriginalString; // Reference.
        public string Target;         // Reference.
        public DateTime Time;         // Value.
    };
}

The optimization in the above code was to replace the class with a struct. This should improve performance by about 2x and reduce memory.

12. Use struct for file offset data
In a database system I developed, file blobs are stored in large files together, and I needed a way to store their offsets. Therefore I had structs with two members: two ints storing positions.

Structs are ideal for this situation: there were 500+ instances of the object, and they only had 2 member fields of value types.

using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Stores Dictionary of structs.
        var _d = new Dictionary<string, FileData>();
        FileData f;
        f.Start = 1000;
        f.Length = 200;
        _d.Add("key", f);
    }

    /// <summary>
    /// Stores where each blob is stored.
    /// </summary>
    struct FileData
    {
        public int Start;
        public int Length;
    }
}

13. Notes on pointers and structs
C# frees us developers from the nightmare that is C pointers, but understanding pointers is important in performance and language work. Pointers, like references, are values that contain the addresses of data.

C-style pointers are blisteringly fast, but their syntax and lack of error checking causes problems. However, the struct keyword in C# gives us more power over references and how fields are stored.

Posted by Jake Kim
TAG c#, struct

코딩 할 때  identifier에 관련된 convention입니다.

1. Class: 반드시 대문자로 시작, 나머진 소문자, 다음 단어는 첫자만 대문자이다.
class MyClass
class UniversalDirectory

2. Interface: interface도 class의 일종이다. 따라서, class와 같은 converntion을 따른다.
interface ShopUser

3. 메소드: 시작은 소문자, 다음 단어는 첫자만 대문자이다.
printUser();
changePassword()

.NET 규칙은 메서드오 Class와 동일한듯... msdn에 메서드 이름이 죄다 대문자로 시작하는것 보면..

4. 변수: 메소드와 같다.

5. Constants(상수): 모두 대문자, 다음 단어 사이에 underscore(_)를 붙여준다.
HEAD_COUNT
MAX_PAGE


다들 잘 알고 계시겠지만, 그래도 다시 한번 상기 시키는 차원에서 글 올립니다.

Posted by Jake Kim

C# 정렬하기 2탄

.NET 2009/03/05 20:02
OrderBy와 LINQ를 이용한 정렬
Posted by Jake Kim

Generics 이란?

JAVA를 주로 사용했던 이유로 범용 메소드를 만들 때면 object로 저장 하는 방법을 많이 이용했다. 이렇게 하면 데이터 타입에 연연하지 않고 파라메터로 넘길 수 있기 때문이다. 물론 동일한 이름의 메소드를 만들 때 파라메터에 의해 결정되는 오버로딩 방법도 있지만 단순히 범용 메소드를 만들 때면 object를 보내는 방법을 선호 했다.

지금까지 object는 가장 상위에 있기 때문에 모든 개체를 받을 수 있고 활용할 수 있기 때문에 편리하다고만 생각 했지 이를 사용함으로써 발생되는 문제는 생각해보지 않았다. 특히 C++의 템플릿방식이 더 귀찮다고 생각 했는데 C#을 배우면서 C++의 템플릿 방법에 대해 다시 한번 생각 해보게 되었고 그 이유로 이 글을 작성한다.

참고로 JAVA에도 Generics라는 기능이 있다. 다만 1.5버전 부터 추가된 기능으로 1.3부터 자바를 써왔던 나는 Generics라는 기능에 대해 깊이 고민해 본적이 없다. 어찌 되었든 C#에서도 Generics라는 기능이 추가 되었고 이 부분은 한번쯤 짚고 넘어 가는게 좋을듯 하다.

우선 C# 2.0에서 가장 기대 되는 기능 중 하나가 Generics라고 한다. JAVA에 저 Generics라는 기능이 나왔을때 말이 많았는 C#에서 조차 이 기능이 추가된걸 보면 C++의 템플릿 기능이 프로그래밍에 여러모로 도움이 되나 보다.

Generics를 사용하는 이유?

MSDN에 따르면, generics를 사용하면 실제 데이터 형식을 커밋 하지 않고도 형식이 안전한 데이터 구조를 정의할 수 있고, 형식별 코드를 복제하지 않고도 데이터 처리 알고리즘을 다시 사용할 수 있기 때문에 성능이 크게 향상되고 코드의 품질이 높아진다고 한다. 개념적으로 generics는 C++ 템플릿과 비슷하지만 구현 및 성능 면에서는 크게 다르다고 하는데 그 부분에 대해서는 설명할 부분이 너무 많아 지기 때문에 여기서는 설명 하지 않도록 하겠다.

자 그렇다면 여기서 말하는 중복을 피하고 성능이 올라가고 코드의 품질이 올라간다는 말은 무엇일까? C++을 해봤다면 알겠지만 템플릿은 꽤나 유용하다. 무형의 데이터 타입을 정의하고 컴파일 할 때 구현되도록 함으로써 소스코드의 중복을 피하고 코드 품질이 좋아진다고 볼 수 있다. 하지만 여기서 말하는 성능이란 무엇일까? 사실 나는 object로 처리 하는 게 낫다고 생각 했는데 MSDN을 보니 여기도 문제가 있는 것 같다.

우선 기본적으로 개체 기반 솔루션에는 두 가지 문제가 있다고 한다. 첫 번째는 성능이다. 값 형식을 지정하지 않고 object로 처리 할 경구 힙의 부담이 늘어나고 성능에 좋지 않은 영향을 주는 가비지컬렉터의 증가로 이루어진다는 것이다. 또한 값 형식 대신 참조 형식을 사용하는 경우에도 개체에서 상호 작용하고 있는 실제 형식으로 캐스팅해야 하고 캐스팅에 따른 추가 작업이 필요하므로 성능이 저하 된다고 한다.

나는 지금까지 JAVA의 가비지컬렉터를 너무 맹신했는지 모르겠다. 물론 지금까지 해왔던 모든 코딩을 하나로 합친다고 하더라도 큰 무리는 없겠지만 앞으로는 이런 부분까지 고려 해야 할 듯 하다.

참고로 잘 이해가 되지 않는 분들은 DB의 TABLE을 설계 할 때 각각의 타입을 정하고 그 크기까지 정확하게 맞춰서 생성하는 것과 같은 맥락이라고 보면 쉽게 이해 될 것이다.
(사실 TABLE 설계도 숫자랑 문자랑 구분 짓고 그냥 냅다 255자까지 들어 가게 해버린 나를 생각 하면 object를 쓰면서 힙을 생각 한다는 게 더 이상했는지도 모르겠다.)




사실 이런 부분을 피하기 위해 각각의 메서드를 만들어 구현할 수 있지만 이렇게 될 때 중복되는 코드가 많아진다는 것이다. C++을 제대로 공부 해봤다면 C#의 generics을 바로 이해 했겠지만, 이제 서야 generics의 기능을 알게 되었다.


C# Generics
참고: http://msdn.microsoft.com/ko-kr/library/ms379564(VS.80).aspx

사실 제 글을 보는 것 보다 MSDN을 보는 게 훨씬 나을 듯 합니다. 글 재주도 없고 본래 있는 글을 다시 풀어서 설명하다 보니 누락 되거나 잘못 언급 된 곳도 있으리라 생각합니다.
어찌 되었든 C#의 generics 기능을 사용하여 구조체를 만들어 자신만의 타입을 사용할 때는 꽤나 강력한 기능이 될 것 같습니다. 거기다 LINQ를 통한 프로그래밍 자체의 SQL문을 사용할 수 있으니 배열 처리시 정렬 등에 굉장히 효과가 있을 듯 합니다.
Java Generics
참고: http://today.java.net/pub/a/today/2003/12/02/explorations.html

Posted by Jake Kim
TAG c#, Generics