AutoMapper(三)

tkbSimplest發表於2015-11-05

返回總目錄


自定義型別轉換

有時,需要完全控制一個型別到另一個型別的轉換。一個型別一點都不像另一個型別,而且轉換函式已經存在了,在這種情況下,你想要從一個“寬鬆”的型別轉換成一個更強壯的型別,例如一個string的源型別到一個int32的目標型別。

這裡有兩個類Source和Destination,要把前者對映到後者,程式碼如下:

public class Source
{
    public string Value1 { get; set; }
    public string Value2 { get; set; }
    public string Value3 { get; set; }
}
public class Destination
{
    public int Value1 { get; set; }
    public DateTime Value2 { get; set; }
    public Type Value3 { get; set; }
}

截至發稿前,官方文件這樣描述的“因為AutoMapper不清楚從string到int,Datetime或Type的對映,如果要嘗試對映的話,AutoMapper就會丟擲異常(在對映時和配置檢查時)”。為了建立 這些型別的對映,我們必須提供自定義的型別轉換器,我們有三種方法這樣做:

 void ConvertUsing(Func<TSource, TDestination> mappingFunction);
 void ConvertUsing(ITypeConverter<TSource, TDestination> converter);
 void ConvertUsing<TTypeConverter>() where TTypeConverter : ITypeConverter<TSource, TDestination>;

但是,我先不實現自定義的型別轉換器試一下:

namespace ThirdAutoMapper
{
    class Program
    {
        static void Main(string[] args)
        {
            Mapper.CreateMap<Source, Destination>();
            var source = new Source
            {
                Value1 = "5",
                Value2 = "05/11/2015",
                Value3 = "ThirdAutoMapper.Source"
            };

            var destination = Mapper.Map<Destination>(source);
            Console.WriteLine("destination.Value1={0}", destination.Value1);
            Console.WriteLine("destination.Value2={0}", destination.Value2);
            Console.Read();
        }
    }
}

出現如下錯誤,但從錯誤看來,只有從string到Type型別對映時,出現了錯誤,其他兩種型別呢?

image

現在我們將源型別和目標型別的第三個屬性Value3註釋掉,同時註釋掉參與對映前的源型別物件的Value3屬性,再來試一下。

image

果然,發現對映成功。也就說說最新版的AutoMapper預設可以將string型別對映為int和DateTime型別了。但是string還是沒辦法對映為Type型別。

對於以上AutoMapper的API給出的三種轉換方法,第一個選擇只是輸入一個源返回一個目標的函式,這對於簡單場合是有效的,但是對於更大的案例會變得難以處理。在更復雜的情況下,我們可以一個自定義的型別轉換器,通過實現ITypeConverter<TSource, TDestination>介面建立:

第一種方法:

public class CustomTypeConverter : ITypeConverter<Source, Destination>
{

    public Destination Convert(ResolutionContext context)
    {
        Source src = context.SourceValue as Source;
        var dest = new Destination
        {
            Value1 = System.Convert.ToInt32(src.Value1),
            Value2 = System.Convert.ToDateTime(src.Value2),
            Value3 = context.SourceType
        };
        return dest;
    }
}

然後給AutoMapper提供一個自定義型別的轉換器或者AutoMapper在執行時能例項化的簡化型別。對於上面的源/目標型別的對映配置就得以實現了:

修改Main方法中的程式碼為:

static void Main(string[] args)
{

    Mapper.CreateMap<Source, Destination>().ConvertUsing<CustomTypeConverter>();
    var source = new Source
    {
        Value1 = "5",
        Value2 = "05/11/2015",
        Value3 = typeof(Source).ToString()
    };

    var destination = Mapper.Map<Destination>(source);
    Console.WriteLine("destination.Value1={0}", destination.Value1);
    Console.WriteLine("destination.Value2={0}", destination.Value2);
    Console.WriteLine(destination.Value3.ToString()==source.Value3);
    Console.WriteLine(destination.Value3);
    Console.Read();
}

 

測試結果如下,對映成功!

image

第二種方法:

每個型別分別實現ITypeConverter介面:

public class DateTimeTypeConverter:ITypeConverter<string,DateTime>
{

    public DateTime Convert(ResolutionContext context)
    {
        return System.Convert.ToDateTime(context.SourceValue);
    }
}

public class TypeTypeConverter : ITypeConverter<string, Type>
{

    public Type Convert(ResolutionContext context)
    {
        return context.SourceValue == typeof(Source).ToString() ? typeof(Source) : typeof(Destination);
    }
}
static void Main(string[] args)
{
    //我看網上很多這種寫法,包括官方文件,但是我這樣寫編譯錯誤,可能是現在的AutoMapper不支援了吧
   // Mapper.CreateMap<string, int>().ConvertUsing( Convert.ToInt32);

    Mapper.CreateMap<string, int>().ConvertUsing((context, intNum) => Convert.ToInt32(context.SourceValue));
    Mapper.CreateMap<string, DateTime>().ConvertUsing(new DateTimeTypeConverter().Convert);
    Mapper.CreateMap<string, Type>().ConvertUsing<TypeTypeConverter>();

    Mapper.CreateMap<Source, Destination>();
    //Mapper.CreateMap<Source, Destination>().ConvertUsing<CustomTypeConverter>();
    var source = new Source
    {
        Value1 = "5",
        Value2 = "05/11/2015",
        Value3 = typeof(Source).ToString()
    };

    var destination = Mapper.Map<Destination>(source);
    Console.WriteLine("destination.Value1={0}", destination.Value1);
    Console.WriteLine("destination.Value2={0}", destination.Value2);
    Console.WriteLine(destination.Value3.ToString()==source.Value3);
    Console.WriteLine(destination.Value3);
    Console.Read();
}

測試結果,同樣完美通過。

image

相關文章