Category Archives: C#

Spring .NET을 소개합니다.

사용자 삽입 이미지

 

 

 

 

 

자바를 하시는 분들은 다들 아실만한 스프링 프레임워크가 있습니다.  C#을 하다 보니깐 스프링 프레임워크의 DI(Dependency Injection)이나 AOP(Aspect Oriented Programming)가 그리워 지더군요.

그래서 찾아보니 C#에서 Spring .NET이라는 프레임워크가 존재 하더군요. 확실히 자바로 만들어진 스프링에 비하면 좀 어설픈 느낌이 있지만 그래도 정말 멋지게 구현되었습니다.

그래서 한번 간단하게 정리해 보겠습니다. Spring .NET은 [이곳] 에서 다운 받으실 수 있습니다. 혹은 소스포지의 주소는 [이곳]입니다.

Spring .NET이란?

  • 객체의 라이프사이클을 관리하기 위해 의존성 주입(Dependency Injection)을 사용하는 경량(Lightweight) 컨테이너
  • 엔터프라이즈급 .NET 어플리케이션 개발을 위한 어플리케이션 프레임워크

Core

Spring .NET Framework의 Core에는 IoC(Inversion of Control) Container와 Base Functionality가 포함되어있습니다. 간단한 예제로 다음과 같은 의존성 부패(Dependency Rot) 문제가 있는 소스가 있습니다.

Public class Human
{
    public Money money;
    public Human() { this.money = GET_MONEY_OBJECT(); }
}

Public class Container
{
    public Human Born()
    {
        return new Human();
    }
}

위의 예제에서는 Human은 Money 인스턴스를 생성하는 방법에 종속됩니다. 다른 말로 Money객체의 생성 여부가 Human에게 달려있다는 것이죠. Container 클래스 제작자는 Money가 Human안에서 생성되는지도 혹은 어떤식으로 사용되는지도 모를 수 있습니다. 그렇다면 DI(Dependency Injection)을 통한 제어 역전(IOC Container)을 사용하는 예제를 보여드리겠습니다.

Public class Human
{
    protected Money money;
    public Money pMoney { set { this.money = value; }} 
}

Public class IoCContainer
{
    public Human Born()
    {
        Human human = new Human();
        Money money = new Money();
        human.pMoney = money;
        return human;
    }
}

정확하게 Money 인스턴스는 Born 메서드에서 생성되어 Human에 Set 됩니다. 이로서 Spring에서 말하는 느슨한 결합이 구현됩니다. 다음에서 이를 실제 적용한 예제를 만들어 보도록 합시다.

using System;
using System.Collections.Generic;
using System.Text;

Namespace HelloApp
{
    class Hello
    {
        public string sayHello(string name)
        {
            return “안녕하세요? “ + name + “씨!”;
        }
    }
}
<?xml version=“1.0” encoding=“utf-8” ?>
<configuration>
    <spring>
        <objects xmlns=“http://www.springframework.net”>
            <object id=“MyHello” type=“HelloApp.Hello”/>
        </objects>
    </spring>
</configuration>
using System;
using System.Collections.Generic;
using system.Text;
using Spring.Context;
using Spring.Context.Support;

Namespace HelloApp
{
    class Program
    {
        static void Main(string[] args)
        {
            IapplicationContext ctx = ContextRegistry.GetContext();
            Hello hello = (Hello) ctx.GetObject(“MyHello”);
            string name = “홍길동”;
            string result = hello.sayHello(name);
            Console.WriteLine(result);
        }
    }
}

결과

사용자 삽입 이미지보시면 코드의 형태는 다를지 몰라도 자바의 그것과 매우 똑같습니다. XML에 객체들을 등록하고 컨텍스트에서 GetObject를 통해 존재하는 객체(Bean)을 가져오게 됩니다.

AOP

관점지향프로그래밍(Aspect Oriented Programming)이라는 것은 처음 접했을때는 매우 이해하기 난해한 개념이었습니다. 물론 지금도 제가 완벽히 이해하고 있는지도 모를 실정이지만, Spring에 적용시켜 보면 무언이구나 하는 생각이 들긴 하는군요.

사용자 삽입 이미지기존의 OOP는 객체간 위와 같은 느낌으로 얽혀 있습니다. 각종 include혹은 import를 사용하여 조립한다는 개념으로 서로 연결되죠. 이는 컴파일 순서에서 서로 얽히게 되며 강한 결합을 통해 서로 강하게 묶여있습니다. 그렇기 때문에 객체들의 추가/제거/교체/수정 등을 할 시에 많은 것을 고려해야 합니다. 위의 그림에서는 오른쪽 녹색 유틸리티 객체들의 내용이 수정, 추가되었거나 기능이 변경되었다면 그것을 사용하는 모든 왼쪽의 파란 메인 객체들의 소스또한 수정될지도 모릅니다.
사용자 삽입 이미지하지만 위의 그림의 느낌은 어떤가요? 유틸리티 객체들은 메인 객체의 배경이 되며 얼마든지 수정/교체가 가능합니다. 하지만 그때에 메인 객체들의 소스는 수정되지 않습니다.  이것이 관점지향프로그래밍의 개념입니다. 예제를 통해 어떻게 구현하는 것인지 알아보도록 하겠습니다.

using System;
using System.Collections.Generic;
using System.Text;
using AopAlliance.Intercept;

namespace HelloAop
{
    class ConsoleLoggingAroundAdvice : IMethodInterceptor {
        public object Invoke(IMethodInvocation invocation) {
            Console.WriteLine("수행전...");
            object retVal = invocation.Proceed();
            Console.WriteLine("수행후...");
            return retVal;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Text;

namespace HelloAop
{
    class ServiceCommand : ICommand
    {
        public object Execute(object arg)
        {
            Console.WriteLine("\n명령 수행 : {0}", arg);
            return null;
        }
    }
}

 

using System;
using System.Collections.Generic;
using System.Text;
using Spring.Aop.Framework;

namespace HelloAop
{
    class Program
    {
        static void Main(string[] args) {
            ProxyFactory factory = 
                new ProxyFactory(new ServiceCommand());
            factory.AddAdvice(new ConsoleLoggingAroundAdvice());
            ICommand command = (ICommand)factory.GetProxy();
            command.Execute("이것은 인자입니다.");
        }
    }
}

ProxyFactory를 이용하여 ServiceCommand를 프록시로 선언합니다. 그후에는 AddAdvice를 이용하여 미리 만들어둔 어드바디스를 추가합니다. 이후에 프록시를 생성하여 명령을 실행하면 “수행전… → 명령수행 : 이것은 인자입니다 → 수행후“가 출력됩니다.

입력되는 인자나 반환된 결과값을 검사하거나 다른 루틴을 얼마든지 추가할 수 있습니다.  위의 과정을 통해 실제로 ServiceCommand 객체의 소스에는 손대지 않고 기능을 추가, 변경 할 수 있게 되었습니다.

사용자 삽입 이미지

위의 그림과 같이 실제로는 별개의 객체들을 프록시로 한데 묶은 다음에 프록시가 메서드 실행 요청을 대리 수령하고 어드바이스를 참고하여 실체 명령을 수행하게 됩니다.

Spring .NET을 도입할 시 얻을 수 있는 장점

  • 중급 이상의 프로젝트 수행 시 각각의 프로그래머 간 개발 스타일이 통일 될 수 있다.
  • 신입 개발자의 교육과정을 줄이고 Spring .NET을 할 줄 아는 개발자를 뽑아 바로 실무에 투입할 수 있다.
  • 각각의 모듈/컴포넌트별로 종속성이 제거 되므로 업그레이드, 추가, 제거가 용이하다.

Microsoft C#의 특징

마이크로소프트의 C#은 앤더슨 헬스버그가 처음 고안하여 여기까지 발전되었습니다.

.NET에 최적화 되어있고 컴포넌트 지향의 프로그래밍 언어입니다. 자바의 단점을 보완하였다고 하지만 그다지 뛰어난점은 모르겠습니다.

C#의 대표적인 특징은 다음과 같은 것이 있습니다.

1. 클래스 (Class) ————————————————————————————
C#에는 C++에서 볼수 있는 클래스가 있습니다. 이 클래스는 Template같은 역할을 하며 객체(인스턴스)로 만들어 사용할 수 있습니다. 클래스에는 객체의 속성(필드)과 행위(메서드)를 결정할 수 있습니다.
[code]class CoffeMaker
{
    public bool onState;
    public void StartCoffeMaker()
    {
        if(onState == true)
        {
            Console.WriteLine(“The CoffeMaker is already on”);
        }
        else
        {
            onState = true;
            Console.WriteLine(“The CoffeeMaker is now on”);
        }
}[/code]

2. 프로퍼티 (Property) ——————————————————————————-
프로퍼티는 클래스의 private 필드를 형식적으로 다루는데 사용되는 일종의 메서드입니다. 값을 지정하는 set과 값을 가져오는 get으로 구성됩니다. 자바의 setter, getter 생각하시면 되겠군요.
[code]class Car
{
    private int _engine;
    public void int engine {
        get { return _engine; }
        set { _engine = value; }
    }
}[/code]

3. 연산자중복 (Operator Overloading) ——————————————————————
연산자 중복이란 시스템에서 제공한 연산자를 프로그래머가 새롭게 정의하는 것을 뜻합니다. 여러말 하는것보다 한개의 예제가 좋겠군요.
[code]class Even {
    int evenNumber;
    public Even(int n)
    {
        // 생성자
        evenNumber = (n % 2 == 0) ? n : n+1;
    }

    public static Even operator++(Even e)
    {
        // ++ 연산자
        e.evenNumber += 2;                    // 다음 짝수
        return e;
    }

    public static Even operator–(Even e)
    {
        // — 연산자
        e.evenNumber -= 2;                  // 이전 짝수
        return e;
    }

    public void PrintEven()
    {
        // 출력 메소드
        Console.WriteLine(“Even Number = ” + evenNumber);
    }
}

class OperatorOverloadingApp
{
    public static void Main()
    {
        Even e = new Even(4);
        e.PrintEven();

        ++e;
        e.PrintEven();

        –e;
        e.PrintEven();
    }
}[/code]

4. 델리게이트 (Delegate) ——————————————————————————
델리게이트란 메소드를 참조하기 위한 방법론으로 자바에서는 없는 개념입니다. invoke를 이용하여 비슷하게 활용할수는 있겠군요. 이 델리게이트를 사용하여 바로 메서드에 접근할 수 있게 됩니다. C++의 포인터와도 비슷한 개념으로 볼 수 있겠지만 좀더 객체 지향적이며 타입 안정적입니다. 주로 이벤트와 쓰레드에서 사용됩니다.
[code]delegate void SampleDelegate();
class DelegateClass
{
    public void DelegateMethod()
    {
        Console.WriteLine(“In the DelegateClass.DelegateMethod …”);
    }
}

class DelegateApp
{
    public static void Main()
    {
        DelegateClass obj = new DelegateClass();
        SampleDelegate sd = new SampleDelegate(obj.DelegateMethod);
        sd();              // invoke obj.DelegateMethod() indirectly
    }
}[/code]

5. 이벤트 (Event) ————————————————————————————-
이벤트란 사용자 행동에 의해 발생하는 사건을 의미합니다. GUI에서 주로 사용되며 객체에 발생한 사건을 자신이나 다른 개체 통지하여 그에대한 처리를 하도록 합니다.
[code]class EventApp : Form
{
    public EventApp()
 {
        // 생성자
        this.Click += new EventHandler(ClickEvent); // 이벤트 처리기 등록
    }
 
    void ClickEvent(object sender, EventArgs e)
 {
        // 이벤트 처리기 작성
        MessageBox.Show(“Hello world”);
    }
 
    public static void Main() {
        Application.Run(new EventApp());
    }
}[/code]

6. 멀티쓰레드 (Multi Thread) ————————————————————————-
하나의 프로그램이 시작, 실행, 종료의 순서를 가진 순차 프로그램이라 할때 이 하나의 흐름을 쓰레드라고 부릅니다. C#에서는 여러개의 쓰레드를 만들어 사용할 수 있습니다.
[code]class ThreadApp {
    static void ThreadBody() {
        Console.WriteLine(“In the thread body …”);
    }


    public static void Main() {
        ThreadStart ts = new ThreadStart(ThreadBody);
        Thread t = new Thread(ts);
        Console.WriteLine(“*** Start of Main”);
        t.Start();
        Console.WriteLine(“*** End of Main”);
    }
}[/code]
위의 실행 결과는 다음과 같습니다
[code]*** Start of Main
*** End Of Main
In the thread body …[/code]
쓰레드 t는 Main과 따로 작동하는 것을 알 수 있습니다.

7. 제네릭 (Generic) ———————————————————————————–
프로그램은 여러종류의 자료형이 있고 이 자료형에 따라 데이터를 표현/저장/연산하는 방법이 다릅니다.
또한 형변환시에 타입캐스팅에 신경을 써야 하는것도 많지요. 제네릭은 미리 이곳에 들어갈 수 있는 타입은 무엇이다 라고 정의하는 것입니다. 자바에서도 5버젼부터 도입되었지요. 자세한 내용은 [ 이곳 ] 을 참조해 보세요^^

8. 예외처리 (Exception) ——————————————————————————-
C#의 예외처리는 예기치 못한 상황이나 예외상황을 다루기 위한 예외처리 기능을 제공합니다. try-catch-finally를 사용합니다.
다음의 예제는 0으로 나누는 상황을 대비한 예외처리 구문입니다.
[code]int SafeDivision(int x, int y)
{
    try
    {
        return (x / y);
    }
    catch (System.DivideByZeroException dbz)
    {
        System.Console.WriteLine(“Division by zero attempted!”);
        return 0;
    }
}[/code]
try는 예외상황을 캐치할 구문이 들어가고 catch에는 예외상황이 들어갔을 경우에 수행할 구문이 들어갑니다.
추가적으로 finally를 통해 예외상황 발생 여부와 상관없이 처리를 할 수도 있습니다.