POSTSHARP 소개

2009/12/29 10:25 / Programming/.NET
사이트 : http://www.postsharp.org/

PostSharp은 여러분의 .NET 코드의 라인수를 줄이고, 논리적은 관계를 분리시켜 코드를 작성할 수 있도록 해줍니다.

쉽게 얘기하면 일반화할 수 있는 코드를 Attribute로 작성할 수 있습니다.

몇가지 예를 들겠습니다.

(1) Trace : 트래이스할 수 있는 사용자 정의 Attribute

public class TraceAttribute : OnMethodBoundaryAspect
{ 
  public override void OnEntry( MethodExecutionEventArgs eventArgs) 
  { Trace.TraceInformation("Entering {0}.", eventArgs.Method);  }

  public override void OnExit( MethodExecutionEventArgs eventArgs)
  { Trace.TraceInformation("Leaving {0}.", eventArgs.Method);   }
}



(2) Async : 특정 함수를 비동기로 만드는 사용자 정의 Attribute

public class AsyncAttribute : OnMethodInvocationAspect
{
  public override void OnInvocation(MethodInvocationEventArgs eventArgs)
  {
    ThreadPool.QueueUserWorkItem(delegate { eventArgs.Proceed(); });
  }
}



(3) GUI Dispatch : 특정 함수를 GUI 쓰레드에서 실행하게 하는 사용자 정의 Attribute

public class GuiThreadAttribute : OnMethodInvocationAspect
{
  public override void OnInvocation(MethodInvocationEventArgs eventArgs)
  {
    DispatcherObject dispatcherObject = (DispatcherObject)eventArgs.Delegate.Target;

    if (dispatcherObject.CheckAccess())
      eventArgs.Proceed();
    else
      dispatcherObject.Dispatcher.Invoke( DispatcherPriority.Normal,
                                          new
Action(() => eventArgs.Proceed()));
  }
}


(4) Exception : 예외를 처리하는 사용자 정의 Attribute

public class ExceptionDialogAttribute : OnExceptionAspect
{
  public override void OnException(MethodExecutionEventArgs eventArgs)
  {
    string message = eventArgs.Exception.Message;
    Window window = Window.GetWindow((DependencyObject) eventArgs.Instance);
    MessageBox.Show(window, message, "Exception");
   
eventArgs.FlowBehavior = FlowBehavior.Continue;
  }

}



(5) Cache : 캐쉬를 하는 사용자 정의 Attribute

public class CacheAttribute : OnMethodInvocationAspect
{
    public override void OnInvocation(MethodInvocationEventArgs eventArgs)
    {
        object value;
        string key = // Compute the cache key (details omitted).

        if (!cache.TryGetValue(key, out value))
        {
            lock ( this )
            {
                if (!cache.TryGetValue(key, out value))
                {  
                    eventArgs.Proceed();
                    value = eventArgs.ReturnValue;
                    cache.Add(key, value);
                    return;
                }
            }
        }
        eventArgs.ReturnValue = value;
    }
}

저는 실제로 INotifyPropertyChanged를 구현할때 일일히 속성을 정의하는게 귀찮아서
어떻게 Attribute로 할 수 없을까 구글로 검색했는데 PostSharp를 사용하면 쉽게 할수 있었습니다.

http://code.google.com/p/propfu/


윈래 이런 코드가

public class PersonLame : INotifyPropertyChanged
   
{
       
private string _name;
       
public string Name
       
{
           
get { return _name; }
           
set
           
{
               
if (value == _name)
                   
return;

                _name
= value;
               
OnPropertyChanged("Name");
           
}
       
}

       
private int _age;
       
public int Age
       
{
           
get { return _age; }
           
set
           
{
               
if (value == _age)
                   
return;

                _age
= value;
               
OnPropertyChanged("Age");
           
}
       
}

       
#region INotifyPropertyChanged Members

       
public event PropertyChangedEventHandler PropertyChanged;

       
#endregion

       
private void OnPropertyChanged(string propertyName)
       
{
           
if (PropertyChanged == null)
               
return;

           
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
       
}
   
}

다음 코드로 정리 됩니다.


[NotifyPropertyChanged]
   
public class PersonAwesome : INotifyPropertyChanged
   
{
       
public string Name { get; set; }

       
public int Age { get; set; }

       
#region INotifyPropertyChanged Members

       
public event PropertyChangedEventHandler PropertyChanged;

       
#endregion

       
[OnPropertyChanged]
       
private void OnPropertyChanged(string propertyName)
       
{
           
if (PropertyChanged == null)
               
return;

           
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
       
}
   
}
크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2009/12/29 10:25 2009/12/29 10:25
Posted by 나는산.
TAGS , , ,

Leave your greetings here.

[로그인][오픈아이디란?]
참조 : http://modeeb.wordpress.com/2009/04/08/c-40-whats-next/

Improved COM Interoperability

C#에서 COM interop 함수들과 작업을 했을때, 여러분은 다음과 같이 불필요한 파라미터에 참조값으로 Missing.Value를 넘겨줬어야 했다.

object filename = "test.docx";
object missing = System.Reflection.Missing.Value;

doc.SaveAs(ref filename,
           ref missing, ref missing, ref missing,
           ref missing, ref missing, ref missing,
           ref missing, ref missing, ref missing,
           ref missing, ref missing, ref missing,
           ref missing, ref missing, ref missing);

인제 C# 4.0에서는 다음과 같이 코딩하면 된다.

doc.SaveAs(filename);

위 코드를 보면 여러분은 ref 생략이 가능하지만, 아직 COM interoperability를 사용하지 않을 경우 ref를 생략하면 안된다. 또, 여러분의 .NET 응용프로그램과 Primary Interop Assembly (PIA)를 포함되어야 했다. C# 4.0에서는 이 작업이 필요없다.
크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2009/12/01 13:01 2009/12/01 13:01
Posted by 나는산.
TAGS

Leave your greetings here.

[로그인][오픈아이디란?]
참조 : http://modeeb.wordpress.com/2009/04/08/c-40-whats-next/

Optional and Named Parameters

C# 4.0의 또 다른 장점은 C나 C++처럼 Optional Paramenter와 Named Parameter를 지원한다는 것이다.

이전 C#에서는 이런 기능들이 지원이 되지 않아 함수 이름이 똑같지만 파라미터가 다른 여러개의 함수들을 볼 수 있었을 것이다. C# 4.0에서는 다음과 같이 함수는 선택적 파라미터를 사용하여 리펙토링 될 수 있다.

public StreamReader OpenTextFile(
         string path,
         Encoding encoding = null,
         bool detectEncoding = false,
         int bufferSize = 1024) { }

위와 같이 OpenTextFile 함수는 선택적 파라미터 하나 이상의 파라미터를 생략해서 사용할 수 있다.

OpenTextFile("foo.txt", Encoding.UTF8);

또한 C# 4.0는 Named Parameter를 지원해서 OpenTextFile 함수는 선택적 파라미터를 생략하면서 특정 파마리터를 정의해서 사용할 수 있다.

OpenTextFile("foo.txt", Encoding.UTF8, bufferSize: 1024);

Named Parameter는 함수 파라미터 순서에서 항상 마지막에서 사용되어야 하지만 Named Parameter 끼리는 순서가 상관 없다.
크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2009/12/01 12:46 2009/12/01 12:46
Posted by 나는산.
TAGS

Leave your greetings here.

[로그인][오픈아이디란?]
참조 : http://modeeb.wordpress.com/2009/04/08/c-40-whats-next/

Dynamically Typed Objects

오늘날 C#에서 여러분은 아래 코드와 같이 특정 클래스의 인스턴스를 가져와서 그 인스턴스의 Add이라는 함수를 호출해서 두 정수의 합을 가져와야 하는 필요하가 있을 수도 있다.

Calculator calc = GetCalculator();
int sum = calc.Add(10, 20);

위의 코드는 만약은 Calculator 클래스가 정적 타입이 아니라 COM, Ruby, Python 아니면 심지어 JavaScript으로 쓰져 있다면 더 재미있어 진다. 우리가 Calculator 클래스가 .NET 객체라고 알고 있지만 정확하게 어떤 타입인지 몰라도 우리는 Reflection을 이용하여 런타임일 때의 속성 타입을 알수 있고 Add 함수를 동적으로 호출할 수 있다.

object calc = GetCalculator();
Type type = calc.GetType();
object result = type.InvokeMember(
         "Add",
         BindingFlags.InvokeMethod,
         null,
         new object[] { 10, 20 });
int sum = Convert.ToInt32(result);

C# 4.0에서는 다음 처럼 간단하게 코딩할 수 있다.

dynamic calc = GetCalculator();
int sum = calc.Add(10, 20);

위 코드 예제에서 우리는 dynamic이라는 정적 타입을 가지는 calc라는 변수를 선언했다. 다음에 Add 함수를 동적으호 호출하여, 호출되는 결과가 동적으로 정적 타입 정수로 변환한다.

크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2009/12/01 12:33 2009/12/01 12:33
Posted by 나는산.
TAGS

Leave your greetings here.

[로그인][오픈아이디란?]

   40 static public Size RatioResizeCalulateHelper(

   41     Size screenSize,

   42     bool useRatio, Size ratioSize,

   43     double spaceTop, double spaceBottom, double spaceLeft, double spaceRight)

   44 {

   45     var calculatedSize = screenSize;

   46 

   47     if (useRatio)

   48     {

   49         if (screenSize.Width > spaceLeft + spaceRight && screenSize.Height > spaceTop + spaceBottom)

   50         {

   51             var realScreenWidth = screenSize.Width - spaceLeft - spaceRight;

   52             var realScreenHeight = screenSize.Height - spaceTop - spaceBottom;

   53 

   54             var ratio = realScreenWidth / ratioSize.Width;

   55             if (realScreenHeight < ratioSize.Height * ratio)

   56             {

   57                 ratio = realScreenHeight / ratioSize.Height;

   58             }

   59 

   60             calculatedSize = new Size(

   61                 ratioSize.Width * ratio + spaceLeft + spaceRight,

   62                 ratioSize.Height * ratio + spaceTop + spaceBottom);

   63         }

   64     }

   65 

   66     return calculatedSize;

   67 }

크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2009/04/01 13:00 2009/04/01 13:00
Posted by 나는산.
TAGS , ,

Leave your greetings here.

[로그인][오픈아이디란?]
얼마전 회사에서 MS Silverlight 2 Beta 2 Training Lab을 보내줬다. 혼자가는 출장이라 심심할 줄 알았지만, 젊은 영국 친국들과 어울려 다녀서 심심하지는 않았다.  
사용자 삽입 이미지

사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지


마이크로소프트 빌딩 1번을 찾았다.
사용자 삽입 이미지


마이크로소프트에서 가장 가까운 호텔... 아침에 와플을 제공한다.
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2008/06/15 02:02 2008/06/15 02:02
Posted by 나는산.

Leave your greetings here.

[로그인][오픈아이디란?]
 - Creation of products that exist in families and are designed to be producted together.
 - Can create different products of different types and in different combinations.

사용자 삽입 이미지

   10         interface IBag

   11         {

   12             string Material { get; }

   13         }

   14 

   15         interface IShoes

   16         {

   17             int Price { get; }

   18         }

   19 

   20         interface IBrand

   21         {

   22             int Price { get; }

   23             string Material { get; }

   24         }

   25 

   26         interface IFactory<Brand> where Brand : IBrand

   27         {

   28             IBag CreateBag();

   29             IShoes CreateShoes();

   30         }

   31 

   32         class Bag<Brand> : IBag where Brand : IBrand, new()

   33         {

   34             private Brand myBrand;

   35             public Bag()

   36             {

   37                 myBrand = new Brand();

   38             }

   39 

   40             public string Material { get { return myBrand.Material; } }

   41         }

   42 

   43         class Shoes<Brand> : IShoes where Brand : IBrand, new()

   44         {

   45             private Brand myBrand;

   46             public Shoes()

   47             {

   48                 myBrand = new Brand();

   49             }

   50 

   51             public int Price { get { return myBrand.Price; } }

   52         }

   53 

   54         class Factory<Brand> : IFactory<Brand> where Brand : IBrand, new()

   55         {

   56             public IBag CreateBag()

   57             {

   58                 return new Bag<Brand>();

   59             }

   60 

   61             public IShoes CreateShoes()

   62             {

   63                 return new Shoes<Brand>();

   64             }

   65         }

   66 

   67         class Gucci : IBrand

   68         {

   69             public int Price { get { return 1000; } }

   70             public string Material { get { return "Crocodile skin"; } }

   71         }

   72 

   73         class Poochy : IBrand

   74         {

   75             public int Price { get { return new Gucci().Price / 3; } }

   76             public string Material { get { return "Plastic"; } }

   77         }

   78 

   79         class Groundcover : IBrand

   80         {

   81             public int Price { get { return 2000; } }

   82             public string Material { get { return "South african leather"; } }

   83         }

   84 

   85         class Client<Brand> where Brand : IBrand, new()

   86         {

   87             public void ClientMain()

   88             {

   89                 IFactory<Brand> factory = new Factory<Brand>();

   90 

   91                 IBag bag = factory.CreateBag();

   92                 IShoes shoes = factory.CreateShoes();

   93 

   94                 Console.WriteLine("I bought a Bag which is made from " + bag.Material);

   95                 Console.WriteLine("I bought some shoes which cost " + shoes.Price);

   96             }

   97         }

   98 

   99         static void Main(string[] args)

  100         {

  101             new Client<Poochy>().ClientMain();

  102             new Client<Gucci>().ClientMain();

  103             new Client<Groundcover>().ClientMain();

  104         }


크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2008/04/21 11:20 2008/04/21 11:20
Posted by 나는산.

Leave your greetings here.

[로그인][오픈아이디란?]
 - A way of creating objects
 - Subclasses decide exactly which class to instantiate

사용자 삽입 이미지

   10         interface IProduct

   11         {

   12             string ShipFrom();

   13         }

   14 

   15         class ProductA : IProduct

   16         {

   17             public string ShipFrom()

   18             {

   19                 return " from South Africa";

   20             }

   21         }

   22 

   23         class ProductB : IProduct

   24         {

   25             public string ShipFrom()

   26             {

   27                 return " from Spain";

   28             }

   29         }

   30 

   31         class DefaultProduct : IProduct

   32         {

   33             public string ShipFrom()

   34             {

   35                 return "not available";

   36             }

   37         }

   38 

   39         class Creator

   40         {

   41             public IProduct FactoryMethod(int month)

   42             {

   43                 if (month >= 4 && month <= 11)

   44                 {

   45                     return new ProductA();

   46                 }

   47                 else if (month == 1 || month == 2 || month == 12)

   48                 {

   49                     return new ProductB();

   50                 }

   51                 else return new DefaultProduct();

   52             }

   53         }

   54 

   55         static void Main(string[] args)

   56         {

   57             Creator c = new Creator();

   58             IProduct product;

   59 

   60             for (int i = 1; i <= 12; i++)

   61             {

   62                 product = c.FactoryMethod(i);

   63                 Console.WriteLine("Avocados " + product.ShipFrom());

   64             }

   65         }

크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2008/04/21 11:19 2008/04/21 11:19
Posted by 나는산.

Leave your greetings here.

[로그인][오픈아이디란?]
LINQ (Language Integrated Query)

LINQ는 C# 3의 심장이다. 이것이 C# 3를 특별하게 만든다. Product를 쿼리하는데 있어서 다음과 같이 LINQ를 사용하면 표현할 수 있다.

   55 List<Product> products = Product.GetSampleProducts();

   56 var filtered = from Product p in products

   57                where p.Price > 10

   58                select p;

   59 foreach (Product product in filtered)

   60 {

   61     Console.WriteLine(product);

   62 }

개인적으로 Where를 사용하는 이전 방법이 쉽다고 생각한다. 그럼 왜 모든 개발자들이 LINQ를 외칠까? 비록 LINQ가 간단한 작업에는 적합하지 않지만, 복잡한 상황이 오면 매우 편리하다는 것이다. 예를 들기 위해 Supplier 타입을 생각해보자. 각 Supplier는 Name(string)과 SupplierID(int)가 있다고 가정하자. 그럼 이전과 같이 가격 필터를 적용하여, Supplier 이름 Product 이름으로 정렬하여 출력하는 루틴을 만든다고 가정하자. 이전 C# 코드로 이것을 작성한다면 입이 벌려질 것이다. 그럼 LINQ를 사용하는 코드를 보자.

   80 List<Product> products = Product.GetSampleProducts();

   81 List<Supplier> suppliers = Supplier.GetSampleSuppliers();

   82 var filtered = from p in products

   83                join s in suppliers

   84                on p.SupplierID equals s.SupplierID

   85                where p.Price > 10

   86                orderby s.Name, p.Name

   87                select new

   88                {

   89                    SupplierName = s.Name,

   90                    ProductName = p.Name

   91                };

   92 foreach (var v in filtered)

   93 {

   94     Console.WriteLine("{0}, {1}", v.SupplierName, v.ProductName);

   95 }


위 처럼 간단히 표현할 수 있는데, 꼭 SQL 같다. 물론 이와 같은 방법으로 XML이나 Database를 처리 할 수 있다. 특히 Database를 다룰 때는 비록 C# 코드로 보이지만 SQL로 처리된다.

또한, LINQ는 유연하다. 직접 자신만의 쿼리 번역기를 만들 수도 있다.


크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2008/03/20 23:31 2008/03/20 23:31
Posted by 나는산.
TAGS

Leave your greetings here.

[로그인][오픈아이디란?]
알수 없는 가격

Product에 가격을 알 수 없는 미리 등록된 Product이 있다고 가정하자. C# 1에서는 어떻게 로직을 짤 수 있을까? decimal이 참조형이면 null을 검사하면 되지만, product에서는 참조값이 아니다. C# 1은 다음 3가지 대안이 있다.

- Decimal을 레핑하는 참조 타입을 생성한다.
- Boolean 플래그를 만든다.
- "Magic Value" (예, decimal.MinValue)를 사용한다.

솔직히 위 3가지 방법은 마음에 들지 않는다. 이것은 C# 2로 넘어오면 Nullable<T> 구조체가 만들어지면서 속성 선언부에서 해결할 수 있다.

decimal? price;
public decimal? Price
{
get { return price; }
private set { price = value; }
}

위 처럼하면 price에 null을 대입할 수 있다. 이렇게 하면 값이 있는지 없는지 검사는 null인지 검사하는 방법과 HasValue 속성을 통해서 검사할 수 있다. 그럼 다음과 같이 값을 알수 없는 product을 걸러낼 수 있다.

   55 List<Product> products = Product.GetSampleProducts();

   56 foreach (Product product in products.Where(p => p.Price == null))

   57 {

   58     Console.WriteLine(product);

   59 }


정리를 하자면,
C# 1 : Choice between extra work maintaining a flag, changing to reference type semantics, or the hack of magic value.
C# 2/3 : Nullable types make the "extra work" option simple and syntactic suger improves matters even further.

크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2008/03/20 23:04 2008/03/20 23:04
Posted by 나는산.
TAGS

Leave your greetings here.

[로그인][오픈아이디란?]