dngchn's [C#]2017. 6. 22. 11:02

위와 같이 Visual Studio 2017에서 무언가 실행했는데, 지금까지 못보던 창이 따라 뜬다.

일단 디버그 모드로 실행했을 경우만 뜨니, 디버깅을 위한 무언가라고 짐작이 된다.

눈에 거슬리면 아래와 같은 옵션에서 체크 해제하면 안뜬다.




Posted by dngchn
dngchn's [C#]2017. 6. 8. 10:30

예제를 통해 MEF 겉을 사알짝 핥아 보자.


1. 먼저 컴포넌트를 정의 해보자.

namespace Contract
{
    public interface IComponent
    {
        string Description { get; }
        string ManipulateOperation(params double[] args);
    }

    public interface IMetadata
    {
        char Symbol { get; }
    }
}

위에서 정의한 컴포넌트는 Description이란 이름으로 컴포넌트에 대한 설명 string과,

ManipulateOperation이라는 메서드(무언가 동작하는)를 갖는다.

추가적으로 IMetadata 인터페이스를 정의하여 Symbol이라는 이름의 프러퍼티를 정의하자.


2. 컴포넌트의 정의대로 특정 기능을 맞추어 외부로 export 하는 놈을 만들자.

using System.ComponentModel.Composition;
using Contract;

namespace ExportMultiplyLib
{
    [Export(typeof(IComponent))]
    [ExportMetadata("Symbol", '*')]
    public class MultiplyOfNumberComponent : IComponent
    {
        public string Description
        {
            get { return "Multiplication of components"; }
        }

        public string ManipulateOperation(params double[] args)
        {
            string result = "";
            double count = 1;

            foreach (double d in args)
            {
                count *= d;

                result += d.ToString() + " * ";
            }

            return result.Trim('*', ' ') + " = " + count.ToString();
        }
    }
}

위에서 보는대로 위 클래스는 IComponent를 구현한다. 클래스의 첫단에 attribute를 두어

IComponent타입으로 export함을 표시하고, 추가적으로 Metadata도 export한다.

이런 attribute 정보는 외부에서 검색(?)할때 판별할 정보가 된다. 즉 이러한 정보를 기준으로

원하는 컴포넌트를 찾게 되는 것이다.


3. 이제 이렇게 export된 놈을 갖다 쓰는 놈을 만들자.

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.IO;
using System.Reflection;
using Contract;

namespace ImportingLib
{
    public class Importer
    {
        [ImportMany(typeof(IComponent))]
        private IEnumerable<Lazy<IComponent, IMetadata>> operations;

        public void DoImport()
        {
            var catalog = new AggregateCatalog();

            catalog.Catalogs.Add(new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)));

            CompositionContainer container = new CompositionContainer(catalog);

            container.ComposeParts(this);
        }

        public int AvailableNumberOfOperation
        {
            get { return operations != null ? operations.Count() : 0; }
        }

        public List<string> CallAllComponent(params double[] args)
        {
            var result = new List<string>();

            foreach (Lazy<IComponent, IMetadata> com in operations)
            {
                Console.WriteLine(com.Value.Description);
                Console.WriteLine(com.Metadata.Symbol);
                result.Add(com.Value.ManipulateOperation(args));
            }

            return result;
        }
    }
}

위의 Importer는 클래스 정의 위에는 특별한 attribute는 없다.

멤버중 "operations"는 IComponent 타입의 컴포넌트를 여러개(ImportMany) 갖는 열거형 멤버이다.

Lazy<IComponent, IMetadata>를 통해 IComponent와 IMetadata타입을 참조한다.


DoImport 메서드에서는 카탈로그를 정의하고 카탈로그에 컴포넌트가 있는 위치를 지정한다.

즉 해당 위치에서 목록(카탈로그)을 구성하라는 의미이다.


CompositionContainer타입의 컨테이너를 생성하며 위에서 준비해 놓은 카탈로그를 기반으로 한다.

최종적으로 컨테이너의 ComposeParts를 호출하여 dll들을 검색하여 컴포넌트를 컨테이너에 담아둔다.


프러퍼티로서 AvailableNumberOfOperation은 컴포넌트의 수를 나타낸다.


메서드 CallAllComponent는 모든 컴포넌트의 동작을 실행시킨다.

동작에는 우선 컴포넌트의 Description을 표시하고,

메타데이터의 심볼을 표시한다.

그리고 각 컴포넌트 고유의 기능을 수행한 결과를 표시한다.


4. 위의 Importer를 실행시켜 보자. 간단한 콘솔프로그램으로 한다.

using System;

namespace MEFTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var t = new ImportingLib.Importer();

            t.DoImport();

            Console.WriteLine("{0} component(s) are imported successfully.", t.AvailableNumberOfOperation);
            var result = t.CallAllComponent(125, 5, 10, 27, 45, 19, 10);
            foreach (string s in result)
            {
                Console.WriteLine(s);
            }
            Console.Read();
        }
    }
}

Importer객체를 하나 생성해서 DoImport를 실행시킨다.

그리고 CallAllComponent를 실행시킨다. 인자로서 숫자들을 넘긴다.

이는 CallAllComponent 메서드의 인자인 double[]로 넘겨진다.

CallAllComponent는 string타입 List를 반환하므로, 각 string을 표시한다.


5. 예시 결과는 아래와 같다.


위에서는 곱셈 컴포넌트 하나만 코드로 살펴봤다. 동일한 방식으로 뺄셈, 덧셈도 만들어 실행한 결과이다.


* 실행시 주의할점.

각 exporter들의 output path를 실행파일의 경로로 일치시켜 주던가, 아니면 컴파일 후 dll들을 실행파일 경로에 복사해 넣어주어야 한다.

각 컴포넌트를 구성하는 dll들은 동적으로 검색되어 실행되므로, 몇가지 dll들을 빼고 실행시키면 존재하는 dll들에 대해서만 실행된다.


* 프로젝터 소스를 첨부한다.

MEFTest.zip


* 코드올리기

찾아보니 티스토리에 코드를 이쁘게 올리는 방법을 소개한 자료가 많더라(SyntaxHighlighter ?).

난 그렇게 하기도 귀찮아서, 아래 온라인 사이트에 코드 붙여넣어 스타일 얻어 다시 복붙했다.

(http://www.pvladov.com/p/syntax-highlighter.html)































Posted by dngchn
dngchn's [C#]2017. 6. 7. 18:16

클래스나 멤버 선언시 Scope(접근 한정자)를 별도로 지정하지 않으면 default로 주어지는 scope는 무엇이 될까?


클래스는 internal

멤버는 private


확인방법은 구글 검색이 아닌,

Visual Studio에서 'Object browser'를 통해 해당 클래스나 멤버를 선택하여 나타나는 정보를 보면 된다.

Posted by dngchn
dngchn's [WPF]2017. 5. 31. 11:52

Collection을 노출하는 방법

Collection을 외부에 노출하는 작업은 종종 필요하고, 다양한 방법이 있겠지만 몇가지 이슈사항을 고려하여 아래와 같은 방법을 추천한다.


Example 1 -> 좋은 예

public class AddressBook
{
    private readonly List<Contact> contacts;

    public AddressBook()
    {
        this.contacts = new List<Contact>();
    }

    public IReadOnlyList<Contact> Contacts { get { return contacts; } }

    public void AddContact(Contact contact)
    {
        contacts.Add(contact);
    }

    public void RemoveContact(Contact contact)
    {
        contacts.Remove(contact);
    }
}

1. 위에서와 같이 IReadOnlyList<T> 또는 IReadOnlyCollection<T>를 이용하여 collection을 외부에 노출시킨다.

순서가 중요하면 IReadOnlyList<T>를 사용,

순서가 중요하지 않다면 IReadOnlyListCollection<T>를 사용.


2. Collection을 조작할 수 있는 메서드를 제공할 것.

이렇게 해야 collection 조작에 대한 컨트롤을 유지할 수 있다(여기저기 다른 곳에서 collection 조작 금지)

이러한 메서드들은 단순하게 collection을 조작하는 일 외에 추가적인 처리를 더할 수 있다(Add메서드에 유일성을 검사하기 위한 판단 추가 등).


3. IEnumerable<T>를 쓰지 말아라, collection을 노출하기 위한 목적이라면.

동작에는 문제 없으나, 성능적인 이슈가 문제 될 수 있음.

 IEnumerable<T>가 단순 collection이 아닌 query를 나타낸다면, 해당 구문 실행 시 마다, 중복되어 query문이 실행될 여지 있음.

* 이에 대한 경고를 'Resharper'에서는 "Possible multiple enumeration of IEnumerable"과 같이 주고 있음.



Example 2 -> 나쁜 예

// This example shows how you should not to expose a collection!
public class AddressBook
{
    public AddressBook()
    {
        Contacts = new List<Contact>();
    }
        
    // Property should not expose the concrete collection type and avoid providing a public setter.
    public List<Contact> Contacts { get; set; }
}

1. 위에서와 같이 구체적인 타입(Contact과 같이)으로 외부에 노출하지 말것.

collection의 타입을 변경해야 한다면 이는 의존성을 증가 시킨다.

외부에서 구체적인 타입의 collection을 얻을 수 있다면 직접 collection을 조작할 수도 있어 collection 조작에 대한 control을 잃어버릴 수 있다.


2. 외부에서 collection을 교체해버리도록 하지 말것.

외부의 코드는 collection의 타입(List or ...)을 고를 책임이 없어야 한다.



IReadOnlyCollection을 사용하면 외부에서 collection을 조작할 수 없다. 그러나 이 의미가 collection 자체가 더이상 변경될 수 없을을 뜻하지는 않는다. 만약 정말 collection이 변하지 말길 바란다면 Immutable Collection을 사용해라.


-끝.


* 참조: http://waf.codeplex.com/discussions/579918

Posted by dngchn
dngchn's [C#]2016. 7. 27. 20:38

https://www.youtube.com/watch?v=TpKcAmaaBts

Posted by dngchn
2016. 6. 28. 09:44

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2016. 6. 20. 16:49

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2016. 6. 20. 16:48

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2016. 6. 10. 16:11

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2016. 6. 10. 13:39

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.