2013-01-08 93 views
0

我想將一堆類型轉換爲一堆其他類型。例如,我有四個類型,SourceASourceBTargetATargetB,我有以下的轉換:使用泛型M:N轉換

  • SourceA => TargetA
  • SourceA => TargetB
  • SourceB => TargetA
  • SourceB => TargetB

基本上,轉換比簡單演員稍高一點。對於上述每種情況,它都需要一個非常自己的策略。

我想做些什麼避免是具有包含類型的方法幾種方法,所以我做想要的東西,如:

ConvertAtoA

或類似的東西。我不想這樣做的原因是因爲這些類型然後被用作字符串,而不是類型本身,所以每當我去重命名一個類型時,都沒有重構支持。假設我將SourceA重命名爲SourceXyz,該方法不會自動更名,但我必須手動執行此操作。

我想要的是一種表達此的通用方式,主要是爲了獲得重構支持。所以基本上的東西,如:

Convert<SourceA, TargetA>(mySourceValue)

這裏的問題是,我結束了它包含一個通用Convert<TSource, TTarget>方法ALL的邏輯ALL類型(這是顯而易見的原因是一個壞主意) 。

我已經看過各種設計模式,包括訪客,策略和責任鏈,但沒有一個引人注目。無論如何,我不確定我是否錯過了一個點。

我該如何解決這個問題?

基本上,兩個主要的目標是:

  • 具有單獨的轉換邏輯的每個組合(沒有複雜的方法)
  • 具有重構支持(無類型字符串)

任何想法?

更新1:我已經考慮過使用AutoMapper,但我不確定它是否按我想要的方式工作。我可以肯定做的是建立一個自定義的轉換器,如

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

,但後來我又具有與轉換器名稱的一部分的類型DateTime。我知道我也可以在這裏使用lambda表達式,但是這又使得代碼變得醜陋,因爲它會變得很長。總之,我擔心我不能擁有一切......

更新2:總是有一個Dictionary<string, string>(雖然內容不同)在左邊,一個你可以通過戴上約束緩解的問題自定義類在右邊。因此,我想直到結束是

dictionary.To<TargetA>() 

,但沒有必要把所有的邏輯轉換爲不同的類型分爲To<T>方法的擴展方法等。

+0

你試過AutoMapper嗎? – daryal

+0

查看問題的更新;-) –

+0

您可以使用FactoryPattern獲取適當的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參數進行方法重載,這很好地工作:-)。