0

我想将一堆类型转换为一堆其他类型。例如,我有四种类型,、SourceA和,我将进行以下转换:SourceBTargetATargetB

  • 源A => 目标A
  • 源A => 目标B
  • 源 B => 目标 A
  • 源 B => 目标 B

基本上,转换比简单的转换要先进一点。对于上述每种情况,它都需要一个非常自己的策略。

我想避免的是有几个方法包含方法名称中的类型,所以我想要这样的东西:

ConvertAtoA

或类似的东西。我不想要这个的原因是因为类型被用作字符串,而不是类型本身,所以每当我去重命名一个类型时,都没有重构支持。假设我重命名SourceASourceXyz,该方法不会自动重命名,但我必须手动执行此操作。

我想要的是一种通用的表达方式,主要是为了获得重构支持。所以基本上是这样的:

Convert<SourceA, TargetA>(mySourceValue)

这里的问题是我最终得到了一个Convert<TSource, TTarget>包含所有类型的所有逻辑的通用方法(由于显而易见的原因,这是一个坏主意)。

我已经看过各种设计模式,包括访问者、策略和责任链,但没有一个吸引人。无论如何,我不确定我是否错过了一点。

我该如何解决这个问题?

基本上,两个主要目标是:

  • 每个组合都有单独的转换逻辑(没有复杂的方法)
  • 具有重构支持(没有类型作为字符串)

有任何想法吗?

更新 1:我考虑过使用 AutoMapper,但我不确定它是否按我想要的方式工作。我可以肯定的是设置一个自定义转换器,例如

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

但话又说回来,我将类型DateTime作为转换器名称的一部分。我知道我也可以在这里使用 lambda 表达式,但这又使代码变得丑陋,因为它会变得很长。反正,我怕我不能拥有一切……

更新 2:您可以通过限制左侧总是有一个Dictionary<string, string>(尽管内容不同)和右侧的自定义类来缓解问题。所以我想结束的是一个扩展方法,比如

dictionary.To<TargetA>()

但无需将转换为不同类型的所有逻辑放入To<T>方法中。

4

2 回答 2

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);
于 2013-01-08T14:12:54.857 回答
1

I got it :-)

Basically, my problem was that I was not able to do method overloading by a generic type parameter. Hence I made a virtue out of necessity and switched to using the TryXXX pattern.

My solution now looks like this:

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; }
    }
}

This way I do not have the type Dog anywhere in a method name, but I can have a separate method for each type I want to convert to.

Adding a new type means just adding the type, and adding a new overload for the extension method TryGet.

The trick is to use the out parameter for method overloading, which works perfectly fine :-).

于 2013-01-08T15:15:57.413 回答