2013-01-08 62 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参数进行方法重载,这很好地工作:-)。