[C# 고급] Generic을 이용한 선택적 Extension Method 설정

노트: 이 아티클은 Microsoft Visual C# 컴파일러 버전 3.0을 기준으로 작성되었습니다. Mono C# 컴파일러에서는 아직 확인되지 않은 기능입니다.


Extension Method는 대체로 특정 형식과 함께 그 형식을 부모 형식으로 사용하는 다른 형식들에 일괄적으로 영향을 주도록 선언이 설정됩니다. 상속 관계에 있어서는 편리하게 사용할 수 있지만, 비슷한 인터페이스들을 하나 이상 동시에 구현하는 여러 종류의 형식을 선택하는 방법이 잘 보이지 않았습니다.


구현하고자 하는 인터페이스의 수가 늘어나게 되면 일정한 패턴을 형성하게 되는데, 이러한 패턴을 Generic에 대입하고, 이러한 형식 패턴에 대하여 Extension Method를 추가하는 방법을 이번 Article에서 소개하고자 합니다.


다음의 예제 코드를 살펴보기로 합니다.


public static class SpecialExtensions
{
    public static string SpecialMethod<T>(this T target)
        where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
    {
        return target.ToString();
    }
}


위의 코드에서 제네릭 형식 T는 where 절의 서술에 따라 다음의 조건을 만족해야 하는 특수성을 가지게 됩니다.



  • struct 키워드가 사용되었기 때문에 값 형식에 속해야 한다.

  • IComparable 인터페이스를 구현하고 있어야 한다.

  • IFormattable 인터페이스를 구현하고 있어야 한다.

  • IConvertible 인터페이스를 구현하고 있어야 한다.

  • IComparable<T> 인터페이스를 구현하고 있어야 한다. 이 때 SpecialMethod<T> 메서드의 인자 T를 그대로 전달하게 된다.

  • IEquatable<T> 인터페이스를 구현하고 있어야 한다. 이 때 SpecialMethod<T> 메서드의 인자 T를 그대로 전달하게 된다.

위의 where 절에서 언급한 이와 같은 인터페이스 구현 패턴은 Primitive Type에 대한 설정으로, 아래와 같이 작동여부가 선택적으로 바뀌게 됩니다. 즉, 구조체이거나 나열 상수라서 모두 SpecialMethod 메서드를 사용할 수 있는 것이 아니고 위의 인터페이스 구현 패턴을 따르는 Primitive Type에 대해서만 SpecialMethod 메서드의 호출이 허용되게 됩니다.


true.SpecialMethod(); // 실패: IFormattable 인터페이스가 구현되지 않음
char.MaxValue.SpecialMethod(); // 실패: IFormattable 인터페이스가 구현되지 않음
Guid.Empty.SpecialMethod(); // 실패: IConvertible 인터페이스가 구현되지 않음
UriFormat.SafeUnescaped.SpecialMethod(); // 실패: IComparable<T>, IEnumerable<T> 인터페이스가 구현되지 않음


byte.MaxValue.SpecialMethod(); // 성공
sbyte.MaxValue.SpecialMethod(); // 성공
short.MaxValue.SpecialMethod(); // 성공
ushort.MaxValue.SpecialMethod(); // 성공
int.MaxValue.SpecialMethod(); // 성공
uint.MaxValue.SpecialMethod(); // 성공
long.MaxValue.SpecialMethod(); // 성공
ulong.MaxValue.SpecialMethod(); // 성공
float.MaxValue.SpecialMethod(); // 성공
double.MaxValue.SpecialMethod(); // 성공
decimal.MaxValue.SpecialMethod(); // 성공


또 다른 방면으로 where 절의 특수 조건 절을 적절히 활용하면, 추상 클래스와 일반 클래스 사이를 선택하여 Extension Method가 달리 선언될 수 있도록 제어하는 것도 가능합니다. 이와 같이 상속 방향 이외의 진행 방향으로 다양하게 Extension Method의 지정 범위를 택하는 기술을 이용하면 좀 더 구체적이고 깊이있는 요구 사항을 처리할 수 있습니다.

C#의 Generic을 다루다보면…

C#의 Generic을 다루다보면 한 가지 불편한 점을 확인할 수 있는데, where 절에 의하여 값 형식인지 아닌지 제한이 가능함에도 실질적인 다른 값 형식들 (대표적으로 Integer, Boolean, Double, 각종 나열상수 및 구조체들)로의 변환이 문법적으로 허용되지 않는 것을 볼 수 있습니다.


형식 안정성에 관한 문제가 발생하기 때문에 이와 같은 동작은 온당한 것이지만 가끔 문제가 됩니다. 다음의 코드를 보기로 합니다.


public static T CastValue<T>(this object o, T fallback)
            where T : struct
        {
            if (o is string)
            {
                string temp = (string)o;


                if (RegexCache.NumberExpression.IsMatch(temp))
                    return (T)Convert.ChangeType(Double.Parse(temp), typeof(T));
                else if (Boolean.TrueString.Equals(temp))
                    return (T)Convert.ChangeType(true, typeof(T));
                else if (Boolean.FalseString.Equals(temp))
                    return (T)Convert.ChangeType(false, typeof(T));

            }


            if (o == null || o is DBNull || o.Equals(DBNull.Value))
                return fallback;
            else
                return (T)o;
        }


Convert.ChangeType 메서드는 이런 경우 진가를 발휘합니다. 비록 형식 안정성의 원칙에 어긋나지만 프로그래머에게 자유를 선사한다고 볼 수 있습니다.

C# 3.0 Preview: Extension Method와 나머지

이번 아티클에서 다루고자 하는 C# 3.0의 새로운 사양 역시도 매우 파격적이다. JavaScript 프로그래밍 언어의 장점(?)을 수용한 새로운 사양이다. 바로 Extension Method가 그것이다. 참고로 JavaScript는 prototype이라고 불리우는 예약된 객체에 새로운 메서드를 정의하고 관리할 수 있다.

Extension Method도 파격적인 언어 사양인데, 기존에 존재하지 않았던 제 3자의 메서드를 동적으로 삽입하는 기술이다. 말 그대로 클래스 스펙에 새로운 메서드를 동적으로 추가할 수 있다는 뜻이다. 그렇다면 이것은 객체 지향 프로그래밍 언어 사양을 완전히 무너뜨리는 기술일까? 한 번 살펴보자.!

Extension Method가 사용된 사례를 보고 싶다면 IList<T> 인터페이스와 호환되는 객체 하나를 만들고 이 객체를 IList<T>로 형 변환하여 나타나는 멤버들 중에 Reverse 메서드를 불러보면 된다. 그러나 System.Linq 네임스페이스는 잠시 제거해보기로 하고 컴파일해보자. 결과가 어떨까?

컴파일은 당연히 실패한다. Reverse라는 메서드가 IList<T> 인터페이스와 부모 인터페이스들 모두에 존재하지 않기 때문이다. 하지만 방금전에 제거했던 System.Linq 네임스페이스를 이번에는 넣어보고 컴파일하자. 그러면 신기하게도 컴파일이 잘 이루어진다.

이것이 의미하는 바가 무엇일까? 진정으로 언어 사양을 깨뜨린 것일까? 다행히도 아니다. 만약 이런식으로 메서드를 아무렇게나 추가할 수 있었다고 한다면 참으로 심각한 일이다. 하지만 특정 네임스페이스 안에 정의된 내용을 포함할지 아니할지의 여부에 따라서 확장 기능을 부여할 수 있도록 하는 것이다.

그러면 이제 본격적으로 Extension Method를 정의하는 방법을 살펴보기로 하자.



using System;
using System.Text.RegularExpressions;


namespace OrcasDrive
{
    public static class StringRegexExtender
    {
        public static Regex ToRegex(this string strInstance, RegexOptions nOptions)
        {
            return new Regex(strInstance, nOptions);
        }


        public static Regex ToRegex(this string strInstance)
        {
            return StringRegexExtender.ToRegex(strInstance, RegexOptions.None);
        }

    }


    internal static class Program
    {
        static void Main(string[] args)
        {
            string strExp = “[0-9]+”;
            Regex oRegex = strExp.ToRegex();
            Console.WriteLine(oRegex.IsMatch(“73820”) ? “Number” : “Not Number”);
        }
    }
}


굵게 강조 표시한 코드들이 바로 Extension Method를 정의하고 사용하는 방법을 설명하는 부분들이다. 우선 Extension Method를 어떻게 정의했는지 살펴보자.

Extension Method는 우리가 일반적으로 정의하는 정적 함수와 사양이 완전히 같고 단 하나의 인수가 더 필요한 것과 반드시 정적 클래스 안에 정의되어있어야 한다는 두 가지 규칙이 추가된 것이 특징이다.

public static Regex ToRegex(this string strInstance)

this string strInstance라는 파라미터가 눈에 띈다. 이것이 바로 Extension Method를 선언하기 위한 컴파일러에게 통지하는 힌트이다. 여기서 this를 제거한다면 그냥 ToRegex 정적 메서드가 작동하기 위하여 필요한 인수로 작동할 것이다. 하지만 여기에 this 키워드를 추가하여 string 형식, 정확히 말하여 System.String 클래스에 대하여 확장 메서드로 추가할 것을 이야기하고 있는 것이다.

여기서 잠시 생각해 볼 것이 있는데, 이와 같이 Extension Method로 선언하지 않아도 이 함수는 기존의 방법대로 사용할 수 있을까? 답은 “그렇다”이다. 기존의 방법대로 사용하던 Extension Method 선언을 이용하여 편입하던 간에 String 클래스에 대하여 이 ToRegex 메서드가 가지는 입장은 완전히 같은 것이다. 다시 말해, String 클래스 안의 private, protected 멤버와 String 클래스가 정의된 mscorlib 어셈블리 안의 internal 멤버들에 대하여 이 메서드는 접근 권한이 없는 것이다. 역으로 이 ToRegex 메서드를 사용하는 다른 코드의 입장에서도 ToRegex에 대해 상대적으로 움직인다. 겉 모양이 파격적이라고 속까지 그런 것은 아니며 철저히 객체 지향 프로그래밍 언어의 기본을 지켜주고 있는 것이다.

이제 위와 같이 선언한 코드가 사용된 예를 살펴보자.


string strExp = “[0-9]+”;
Regex oRegex = strExp.ToRegex();
Console.WriteLIne(oRegex.IsMatch(“73820”) ? “Number” : “Not Number”);

아주 그럴듯하고 멋진 코드가 나왔다.

참고로 this 키워드를 붙일 수 있는 인수는 해당 Extension Method에 하나만 허용된다. 그리고 this 키워드가 붙을 인수는 반드시 함수의 제일 처음에 와야 한다는 강제가 따른다.

자동 프로퍼티는 C# 3.0에서 언어적으로 새롭게 추가된 기능으로 따로 멤버 변수를 선언하고 이것을 캡슐화하는 프로퍼티를 만드는 수고 없이 간단하게 자동화할 수 있는 기능이다. 다음이 그 사용 예이며 매우 간단하다.


public string AutoPropTest
{
  get; set;
}

위와 같이 선언하기만 하면 C# 3.0의 경우 다음과 같은 의미를 가진다.


public static AutoPropTest
{
   get { return this.m_strValue; }
   set { this.m_strValue = value; }
}

그리고 C# 3.0에서 마지막으로 살펴보고자 하는 기능인 익명 배열도 참 간단하다.

var obj = new [] { “test”, “test 2”, “test 3” };

익명 배열은 익명 형식과 마찬가지로 코드 상에서 형식을 미리 지정하지 않고 컴파일 타임때 형식을 결정하는 기술이다. 위의 코드에서는 string 인스턴스로만 구성된 1차원 배열을 지정하였으므로 실제로는 string[] 형식으로 치환된다. 익명 배열 원소 중에 상속 관계와 관련이 없거나 완전히 다른 형식의 원소가 하나 이상 포함되면 형식을 결정할 수 없다는 오류가 발생하게 된다.

이번 아티클을 기점으로 C# 3.0의 모든 새로운 기능들은 한 번씩 둘러볼 수 있었다. 아티클을 편집하는 현 시점에서 Visual Studio 2008이라는 정식 명칭을 가진 새 버전의 Visual Studio 제품 시리즈가 베타 2 버전으로 배포되고 있으니 언제든지 시험해볼 수 있다.

C# 3.0 Preview – var 키워드와 익명 형식

C# 3.0에서 가장 충격적으로 보였던 부분이었지만 이내 정확한 규정을 보고 실체를 알게 된 다소 놀라운 언어 사양이었다. 하지만 var의 용법은 우리가 알던 스크립트 언어에서의 사용법과 별반 차이가 없다는 것은 분명하다.

스크립트 및 인터프리팅 언어의 경우 형식이 동적으로 변형되는 기술을 지원하기 위하여 형식을 고정할 필요도 없고 고정해서는 안되는 특성을 가지고 있다. 이러한 풍부함 덕분에 스크립트 언어는 상당수의 노가다를 면할 수 있도록 도와주고는 있지만 컴파일 언어와는 달리 있는 그대로를 받아들일 수 없기 때문에 분석하고 해석하는데에 지출되는 비용이 만만치 않다는 단점이 있다.

var는 플랫폼이나 사용 환경에 따라서 조금씩 의미가 달라져왔지만 일반적으로 형식이 결정되지 않은 어떤 임의의 변수를 뜻한다. 보통은 var에 담기는 변수의 형식은 런타임, 그러니까 프로그램을 실행하는 도중에 결정된다고 알려져있다. 그러나 C# 3.0은 이 관점을 조금 다르게 보고 있는데 런타임이 아닌 컴파일 타임에서 이것을 해결하려고 하고 있다.

아래의 코드를 컴파일하고 그 결과로 만들어진 닷넷 어셈블리를 Reflector나 ILDASM 등으로 쪼개어보면 정확히 결과를 알 수 있다.


var oBuffer = new System.Text.StringBuilder();
oBuffer += “Welcome “;
oBuffer += “to “;
oBuffer += “C# 3.0!”;
oBuffer += Environment.NewLine;

어차피 컴파일 타임에 가서 정확한 형식이 결정되기 때문에 런타임에 손해를 끼칠 걱정을 할 필요도 없다보니 var를 남발해도 괜찮지 않을까 싶기도 하지만 우리가 일상적으로 사용하는 프레임워크들 중에서 딱 한 곳만은 var의 사용을 자제해야할 것으로 생각되는 곳이 있다. 바로 네트워크 서버 관련 프로그래밍과 ASP .NET 관련 기술들이다. 미리 만들어진 어셈블리를 불러다 쓰는 것이야 자유이지만 var 키워드를 남발하는 코드를 컴파일하는 시간까지 Service Time에 포함되는 종전의 ASP .NET 사이트에서는 별로 현명하지 못한 선택일 수 있다.

var 키워드를 어떻게 사용하던간에 그것은 프로그래머 개인의 문제이지만 종전의 C# 1.0과 C# 2.0에는 이런 규칙이 없었으므로 기존 코드와의 호환성을 위해서라도 var 키워드는 지금부터 설명하는 LINQ와 관련된 익명 형식에서만 사용하는 것이 현명하리라 본다.

익명 형식이란 C# 2.0에서 소개되었던 익명 대리자와는 또 다른 것으로 훨씬 제약이 심하다. 익명 형식 자체의 메리트보다는 LINQ와의 연동 때 편리하게 사용할 수 있도록 해주는 지원 사격용 언어 규약이라고 할 수 있다. 용법은 다음과 같다.


var oData = new { /* 읽기 전용 프로퍼티 이름 / = / 현재 문맥에서 사용하는 변수, 함수 반환 값 */, … };
형식을 정할 수 없다는 것을 감안할 때 var 키워드가 당연히 필요하다. 하지만 object에 담아도 문제는 없지 않았을까? 구조적으로 본다면 틀린 말도 아니다. 하지만 var는 컴파일 타임때 완전한 형식을 결정해주는 수단이라고 하였는데 object를 사용한다면 실제 형식을 유추하기 위해서 너무 많은 오버 헤드를 런타임에서 수반하게 되어있다. 그러므로 var 키워드를 정말 올바르게 사용하고자 한다면 위와 같은 유형이 정답인 것이다.

그리고 그냥 프로퍼티 이름이 아니라 왜 읽기 전용일까? 이것이 바로 절제의 미학이고 정확한 언어 사양 선정이라고 본다. 익명 형식이라 해서 아무렇게나 선언할 수 있게 허용한다면 C#의 기본 틀이 완전히 무너지는 양상을 띄게 된다.

더 중요한 것은 코드 문맥에서 사용할 수 있는 함수의 반환값, 변수의 대입을 지원하는 것인데 상당 부분의 코드가 감추어져있지만 이것을 위와 같이 인라인 표기로 한 번에 표현할 수 있도록 한 것이다. 물론 컴파일을 했을 경우 코드의 크기가 늘어날 것을 걱정한다면 역시 바람직하지는 않다. 하지만 편의성의 관점에서 접근해본다면 그렇게까지 손해갈 일은 아닐 것이다.

자, 그러면 한 가지 수수께끼가 드러난다. 익명 형식을 가지고 제네릭을 사용할 수 있을까?

물론 이와 같이 끝난다면 사용할 수 없다. 하지만 우회적으로 LINQ를 사용하면 IEnumerable<T>에 포장된 컬렉션을 탐색할 수 있다. 여기까지가 익명 형식을 통한 제네릭 사용의 전부인 셈이다. 그리고 당연히 이렇게 사용하는 LINQ의 결과 집합도 형식은 알 수 없으므로 var에 담겨야 합당한 것이나 통상적으로 LINQ의 결과 집합은 IEnumerable<T> 인터페이스와 호환된다는 것을 상식적으로 알고 접근하는 것 뿐이다. 🙂

다음 아티클에서는 C# 3.0에서 좀 더 쓰기 쉽고 간략하게 바뀐 변형 문법들을 살펴보기로 한다.

C# 3.0 Preview – Lambda Expression

개인적으로 C# 3.0이 파이썬의 영향을 많이 받았다고 생각되는 부분이 바로 이 부분이다. 파이썬에도 Lambda Expression이 존재하고 있고 용법이 너무나 유사하기 때문이다.

Lambda Expression은 C# 2.0에서 도입되었던 Anonymous Delegate (익명 대리자)를 좀 더 실용적이고 쓰기 쉽게 많든 것으로 Lambda Expression은 컴파일 과정에서 대리자로 치환된다. Lambda Expression의 용법은 다음과 같다.

(매개 변수 리스트) => (인라인 표현식)

매개 변수 리스트에는 매개 변수가 하나도 없을 수도 있고 여러 개의 매개 변수가 올 수도 있다.

Predicate<int> oTest = x => x % 2 == 0;
Console.WriteLine(oTest(2).ToString());
Console.WriteLine(oTest(3).ToString());

홀수와 짝수를 판정하는 지극히 일반적인 작업을 Lambda Expression으로 만든 것이다. 이전의 익명 대리자에 비해 훨씬 간단하고 알아보기 쉬운것은 물론 수학 공식같은 표기법이므로 상당히 친숙하다. Lambda Expression이 대리자 안에 담길 수 있다는 것을 보이기 위하여 닷넷 프레임워크 2.0부터 제공되는 기본 대리자 형식인 Predicate를 사용하여 Lambda Expression을 담았다. 왜 담길 수 있었는지를 따져보기 위하여 디스어셈블해보면 예상했던 그대로 익명 대리자를 사용한 것을 알 수 있다.

익명 대리자는 한 줄이 넘는 프로그램 코드를 담을 수 있었기 때문에 확장성은 좋지만 과연 실용적인가에 대한 의문이 많았다. 하지만 Lambda Expression은 참으로 알차다고 본다. 내부적으로 익명 대리자로 치환되기 때문에 (그것도 다소 큰 분량의 코드로서) 코드 크기에 민감한 상황에서는 적절하지 않은 선택일 수 있지만 일반적인 목적 달성을 위해서라면 그렇게까지 심각하게 따져야 할 이유가 없을 것이다.

C# 3.0은 대체로 C# 2.0의 기능을 내부적으로 다시 사용하고 있으며 언어적인 차원에서만 업그레이드한 성격이 강하다. C# 3.0의 문법이 낯설다면 C# 2.0에서 추가한 기능이 C# 3.0에서 어떻게 반영될지 심층적으로 살펴볼 본 아티클 시리즈들을 통하여 친해져보면 좋지 않을까 싶다.

다음 아티클에서는 C# 3.0에서 가장 논란(?)이 되었던 var 키워드의 실체를 보기로 한다. var 키워드에 대해서는 개인적으로 오해를 풀었다는 이야기를 블로그에 올린적이 있다.

C# 3.0 Preview – LINQ

C# 3.0이 닷넷 프레임워크 3.5와 함께 배포되기로 함에 따라 역시 가장 많은 주목을 받고 있는 부분이 있다면 그것은 아마도 LINQ와 Lambda Expression일 것이다.

현재까지 살펴본 바로는 LINQ는 데이터 액세스에 상당하 초점이 맞추어져있었다. 또한 LINQ는 Boxing과 Unboxing으로 인하여 지출되는 성능 상의 비용을 없애기 위하여 C# 2.0의 Generic을 고도로 활용하는 모습을 보여주는데 다음의 코드가 그러하다.

public static IEnumerable<Employee> PopulateRandomInfo(int nCount)
        {
            Random oRandom = new Random();


            for (int i = 0; i < nCount; i++)
                yield return new Employee(“Test” + i.ToString(), (float)oRandom.NextDouble() * 100);
        }

IEnumerable<Employee> query = from x in Employee.PopulateRandomInfo(128)
                        where x.EmployeeSalary > 50.0f
                        where x.EmployeeName.StartsWith(“Test”)
                        orderby x.EmployeeSalary descending
                        orderby x.EmployeeName ascending
                        select x;

Employee 클래스의 정적 메서드인 PopulateRandomInfo 메서드는 C# 2.0의 yield return을 사용하여 언어 수준에서 컬렉션을 만들어서 반환하는 것을 볼 수 있다. 그리고 이렇게 만들어진 컬렉션을 LINQ에서는 바로 활용할 수 있다.

LINQ의 대략적인 구조를 보면 그리 낯설지 않은 모습임을 알 수 있는데 FROM ~ WHERE ~ SELECT 순으로 끝나는 구조이다. 어떤 필드를 조회할 것인지를 먼저 선택해야하는 SQL과는 달리 LINQ에서는 어떤 데이터 소스를 사용할 것인지를 (from) 묻는 것이 더 우선순위가 높다. 그리고 그 데이터 소스로부터 조건을 두고 (where), 데이터를 정렬하거나 (order by), 데이터를 그룹화한 상태로 (group ~ by) 원하는 데이터를 가져오는 (select) 형태이다.

from 절이 의미하는 바를 생각해보면 foreach와 꽤 유사하다. x라고 하는 미리 가정된 변수와 이 변수의 제한 범위를 설정하는 것이 꼭 foreach와 모양새가 비슷하다. 그리고 뒤이어 나타나는 where, orderby, select 등의 구절은 from에서 정한 변수 x를 기준으로 서술되는 것이다. 또한 from 절에서 지정할 수 있는 데이터 소스는 foreach 구문에서와 마찬가지로 “나열될 수 있는” 데이터 소스여야 한다.

현재 버전에서, LINQ 질의문 자체는 함수처럼 담아지는 항목이 아닌 즉시 실행되는 문장 (Statement)으로 취급되고 있고 단지 우리는 LINQ 질의문의 수행 결과를 IEnumerable<T> 인터페이스 형식으로 받아볼 수 있는 것일 뿐이다.

LINQ는 이와 같이 사용함으로서 우리가 일상적으로 사용하는 데이터 프레젠테이션 관련 작업을 너무나도 간단하게 풀어내고 있다. 또한 LINQ 역시 질의문의 구조를 취하고 있기 때문에 프로그래밍 코드로 다 풀어내기 어려운 복잡한 정렬 조건 설정도 처리하기가 매우 용이하다.

LINQ에 이어서 주목을 받고 있는 또 다른 C# 3.0의 언어적 확장 기능인 람다 표현식을 다음번에는 살펴보기로 할까 한다.

C# 3.0의 var에 대한 오해를 풀다

이번 주말에는 C# 3.0에서 개인적으로 가장 불만이라고 생각했던 var에 대한 용법을 상세히 알아봤다. var라니. 처음 C# 3.0 스펙을 보고 “헉 -_-“하고 놀랐던 부분이다. 분명히 컴파일언어라고 생각했는데 이런식으로 Variant Type을 언어 스펙에 집어넣다니. 스크립트 언어도 아닌데 말이다.

하지만 내 예상과는 달리 var의 용법은 크게 다른 것이었다. var는 단지 System.Object의 객체를 만들어 그 안에 무언가를 집어넣고 꺼내온다는 Boxing과 Unboxing 작업을 최소화할 수 있는 또 다른 수단이었다. C# 2.0에서, System.ValueType에 대한 Boxing과 Unboxing을 최소화하기 위하여 소개한 것이 Nullable Type (System.Nullable<T>)이었다면, C# 3.0에서는 Compile-Time의 수준에서 동적으로 형식을 결정하도록 하는 것이 바로 var 키워드의 용법이었다. 다시 말해, Runtime에 대해서는 털끝하나 손해주는 일이 없다는 것이며 대신 그 댓가를 컴파일러가 지불하는 셈이다.

단독으로 사용하는 var가 어떤 관점이나 측면에서 유용하고 효과적인지 아직은 모르겠다. 하지만, var를 단독으로 쓰는 경우보다는 C# 3.0의 다른 기능들 (LINQ, Lambda Expression 등)의 보조를 맞추기 위하여 사용하는 것이 좀 더 적절하지는 않을까라는 결론을 유추할 수 있었다.