2013-01-08 4 views
0

여러 종류의 유형을 다른 유형으로 변환하려고합니다.M : N 제네릭을 사용하는 변환

  • 전원 A => TargetA
  • 전원 A => TargetB
  • 전원 B => TargetA
  • : 예, 나는 다음과 같은 변환을해야합니다, 네 가지 유형, SourceA, SourceB, TargetATargetB이 SourceB => TargetB

기본적으로 변환은 단순 형 변환보다 약간 더 고급입니다. 위의 경우 각각에 대해 고유 한 전략이 필요합니다.

나는이 방법 이름의 유형을 포함하는 여러 가지 방법을 가지고있다 피하기 하고 싶은, 그래서 나는 같은 것을하지 을 무엇 :

ConvertAtoA

또는 이와 유사한 일을 . 내가 이것을 원하지 않는 이유는 타입이 타입 자체가 아닌 문자열로 사용되기 때문입니다. 그래서 타입 이름을 바꿀 때마다 리펙토링 지원이 없습니다. SourceASourceXyz으로 바꾸 었다고 가정하면이 메서드는 자동으로 이름이 변경되지 않지만 수동으로해야합니다.

내가 표현하고자하는 것은 주로 리팩터링 지원을 받기 위해 이것을 표현하는 일반적인 방법입니다. 그래서 기본적으로 뭔가 같은 :

Convert<SourceA, TargetA>(mySourceValue)

여기서 문제는 내가이 포함 된 일반적인 Convert<TSource, TTarget> 방법으로 끝낼 것입니다 ALL (분명한 이유에 대한 나쁜 생각이다) ALL 유형에 대한 논리 .

나는 방문객, 전략 및 책임 체인을 포함하여 다양한 디자인 패턴을 이미 살펴 보았지만 그 중 누구도 매력을 발견하지 못했습니다. 어쨌든, 내가 그 지점을 놓쳤는 지 확실하지 않습니다.

는이 문제를 어떻게 해결할 수 있을까?

기본적으로 두 가지 목표는 :

  • 이 (더 복잡한 방법)
  • 지지체 (문자열 등없는 타입)

어떤 아이디어 리팩토링 갖는 조합마다 별도의 변환 논리를 갖지 않는 ?

업데이트 1 : AutoMapper 사용을 고려해 보았지만 원하는 방식대로 작동하는지 확신 할 수 없습니다. 내가 확실히 할 수있는 것은

Mapper.CreateMap<string, DateTime>().ConvertUsing(new DateTimeTypeConverter()); 

과 같은 사용자 정의 변환을 설정하지만 다시 나는 컨버터 이름의 일부로 유형 DateTime을 가지고있다.나는 여기에서도 람다 식을 사용할 수 있다는 것을 알고 있지만, 이것은 매우 길어질 것이므로 코드가 추악해진다. 어쨌든, 나는 ... 나는 모든 것을 가질 수 없다는

업데이트 2를 두려워 : 왼쪽과에 (비록 다른 내용) 항상 Dictionary<string, string> 있다는 것을 당신은 제약에 넣어 문제를 완화 할 수 오른쪽 맞춤 수업. 그래서 내가 함께 결국 싶습니다

dictionary.To<TargetA>() 

로하지만 To<T> 방법으로 다른 종류로 변환하기위한 모든 논리를 넣을 필요없이 이러한 확장 방법이다.

당신은 대상 유형을 만든 다음 일반 매개 변수 유형에 따라 몇 가지 방법에 해당 객체를 작성 위임합니다 확장 메서드를 만들 수 있습니다
+0

AutoMapper를 사용해 보셨습니까? – daryal

+0

질문의 업데이트보기 : –

+0

FactoryPattern을 사용하여 apropriate Converter를 구할 수 있습니다. – TGlatzer

답변

2

:

public static class Extensions 
{ 
    public static T ConvertTo<T>(this Dictionary<string, string> dictionary) 
     where T : new() 
    { 
     dynamic target = new T(); 
     return (T)Extensions.FillFrom(target, dictionary); 
    } 

    private static object FillFrom(this object obj, 
            Dictionary<string, string> dictionary) 
    { 
     var message = "Conversion to " + obj.GetType() + " is not supported."; 
     throw new NotSupportedException(message); 
    } 

    private static TargetA FillFrom(this TargetA target, 
            Dictionary<string, string> dictionary) 
    { 
     // throw exception if required keys not found 
     target.Foo = dictionary["foo"]; 
     return target; 
    } 

    private static TargetB FillFrom(this TargetB target, 
            Dictionary<string, string> dictionary) 
    { 
     // throw exception if required keys not found 
     target.Bar = dictionary["bar"]; 
     return target; 
    } 
} 

사용법 : 당신이 할 수있는

var targetA = dictionary.ConvertTo<TargetA>(); 

같은 접근 방식을 일부 변환기 클래스와 함께 사용하십시오 (확장 메서드가 마음에 들지 않는 경우). 또한 FillFrom 메서드를 공개로 설정할 수 있습니다. 당신이 그들을 좋아 사용할 수 있습니다보다 :

var target A = new TargetA().FillFrom(dictionary); 
+0

질문 :-)의 업데이트보기 –

+0

@GoloRoden 그래서 문자열과 DateTime과 같은 유형이 완전히 다릅니다. –

+0

예, 실제로는 왼쪽에 'Dictionary '이고 오른쪽에 사용자 정의 클래스가 있습니다. –

1

을 나는 기본적으로, 내 문제는 내가 제네릭 형식 매개 변수에 의해 메소드 오버로딩을 할 수 없음을했다

:-)를 얻었다. 그러므로 필연적으로 미덕을 만들고 TryXXX 패턴으로 전환했습니다.

내 솔루션은 이제 다음과 같습니다

using System; 
using System.Collections.Generic; 

namespace HelloWorld 
{ 
    public class Program 
    { 
     public static void Main() 
     { 
      Dictionary<string, string> dict = new Dictionary<string, string> { 
       { "a", "b" } 
      }; 

      Dog dog; 
      if (dict.TryGet (out dog)) 
      { 
       Console.WriteLine(dog.Color); 
      } 
     } 
    } 

    public static class ExtensionMethods 
    { 
     public static bool TryGet(this Dictionary<string, string> dictionary, out Dog dog) 
     { 
      dog = new Dog(); 
      dog.Color = "black/white"; 
      return true; 
     } 
    } 

    public class Dog 
    { 
     public string Color { get; set; } 
    } 
} 

이 방법 난 아무데도 메소드 이름의 유형 Dog이없는,하지만 난로 변환 할 각 유형에 대해 별도의 방법이있을 수 있습니다.

신형 단지 유형을 추가 수단을 추가, 확장 방법 TryGet위한 새로운 과부하 추가.

비결은 완벽하게 잘 :-) 작동 방법 오버로드에 대한 out 매개 변수를 사용하는 것입니다.