AutoMapper(三)

返回總目錄html


自定義類型轉換

有時,須要徹底控制一個類型到另外一個類型的轉換。一個類型一點都不像另外一個類型,並且轉換函數已經存在了,在這種狀況下,你想要從一個「寬鬆」的類型轉換成一個更強壯的類型,例如一個string的源類型到一個int32的目標類型。app

這裏有兩個類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>;

可是,我先不實現自定義的類型轉換器試一下:spa

複製代碼
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類型映射時,出現了錯誤,其餘兩種類型呢?code

image

如今咱們將源類型和目標類型的第三個屬性Value3註釋掉,同時註釋掉參與映射前的源類型對象的Value3屬性,再來試一下。htm

image

果真,發現映射成功。也就說說最新版的AutoMapper默承認以將string類型映射爲int和DateTime類型了。可是string仍是沒辦法映射爲Type類型。對象

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

第一種方法:接口

複製代碼
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

 

 

 

 

 

 

 

 

目前實如今AutoMapper中,已經修改了ITypeConverter接口中的Convert方法,所以從新寫了方法一和方法二的實現
方法一:

1
2
3
4
5
6
7
8
9
10
11
public  class  CustomTypeConverter : ITypeConverter<Source, Destination>
    {
        public  Destination Convert(Source source, Destination destination, ResolutionContext context)
        {
            destination =  new  Destination();
            destination.Value1 = System.Convert.ToInt32(source.Value1);
            destination.Value2 = System.Convert.ToDateTime(source.Value2);
            destination.Value3 = source.GetType();
            return  destination;
        }
    }


方法二:

1
2
3
4
5
6
7
public  class  TypeConverter : ITypeConverter< string , Type>
     {
         public  Type Convert( string  source, Type destination, ResolutionContext context)
         {
             return  Type.GetType(source);
         }
     }
相關文章
相關標籤/搜索