使用 Mapster 處理物件對應
平時都會使用AutoMapper做物件對應處理,這次拿新玩具Mapster玩玩
筆記一下做法
Install-Package Mapster
1.兩個屬性名稱相同的物件轉換
public class ClassA
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Count { get; set; }
}
public class ClassB
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public void BasicConvert()
{
var classA = new ClassA()
{
Id = 123,
Name = "",
Price = 23.3m
};
var classB = classA.Adapt<ClassB>();
classB.Should().BeEquivalentTo(new ClassB()
{
Id = 123,
Name = "",
Price = 23.3m
});
}
2.屬性名稱相同但型別不同的物件
public class ClassA
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Count { get; set; }
}
public class ClassC
{
public string Id { get; set; }
public string Name { get; set; }
public string Price { get; set; }
public int Count { get; set; }
}
public void BasicConvert_Type_Not_Same()
{
var classA = new ClassA()
{
Id = 123,
Name = "",
Price = 23.3m,
Count = "3",
};
var classC = classA.Adapt<ClassC>();
classC.Should().BeEquivalentTo(new ClassC()
{
Id = "123",
Name = "",
Price = "23.3",
Count = 3,
});
}
3.從字典轉換為物件
public class ClassA
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Count { get; set; }
}
public void BasicConvert_Dictionary()
{
var dictionary = new Dictionary<string, string>()
{
{ "Id", "1" },
{ "Name", "Test" }
};
var classA = dictionary.Adapt<ClassA>();
classA.Should().BeEquivalentTo(new ClassA()
{
Id = 1,
Name = "Test"
});
}
4.集合的轉換
public class ClassA
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Count { get; set; }
}
public class ClassB
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public void BasicConvert_List()
{
var classAs = new List<ClassA>()
{
new ClassA(){Id = 1,Name = "Test"},
new ClassA(){Id = 2,Name = "Test2"},
};
var classBs = classAs.Adapt<List<ClassB>>();
classBs.Should().BeEquivalentTo(new List<ClassB>()
{
new ClassB() { Id = 1, Name = "Test" },
new ClassB() { Id = 2, Name = "Test2" },
});
}
5.從靜態類別自定義轉換邏輯
public void CustomConvert()
{
TypeAdapterConfig<ClassA, ClassB>
.NewConfig()
.Ignore(b => b.Price)
.Map(b => b.Name, a => $"{a.Id}_{a.Name}");
var classA = new ClassA()
{
Id = 1,
Name = "Test",
Price = 12.34m
};
var classB = classA.Adapt<ClassB>();
classB.Should().BeEquivalentTo(new ClassB()
{
Id = 1,
Name = "1_Test",
Price = 0m,
});
}
6.包含子物件的物件轉換
public class ClassD
{
public int Id { get; set; }
public ClassB ClassB { get; set; }
}
public class ClassB
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public class MyClassA
{
public int Id { get; set; }
public MyClassB ClassB { get; set; }
}
public class MyClassB
{
public int Id { get; set; }
public string Name { get; set; }
}
public void InnerClass()
{
TypeAdapterConfig<ClassB, MyClassB>.ForType();
var classD = new ClassD
{
Id = 1,
ClassB = new ClassB
{
Id = 2,
Name = "Test",
Price = 23m
}
};
var myClassA = classD.Adapt<MyClassA>();
myClassA.Should().BeEquivalentTo(new MyClassA()
{
Id = 1,
ClassB = new MyClassB()
{
Id = 2,
Name = "Test"
}
});
}
7.從instance config自定義轉換邏輯
public class ClassA
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Count { get; set; }
}
public class ClassB
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public void Basic()
{
var config = new TypeAdapterConfig();
config.NewConfig<ClassA,ClassB>()
.Map(b=>b.Id,a=>a.Id+1)
.Map(b=>b.Name,a=>"Name");
var classA = new ClassA()
{
Id = 1,
Name = "Test"
};
var classB = classA.Adapt<ClassB>(config);
classB.Should().BeEquivalentTo(new ClassB()
{
Id = 2,
Name = "Name"
});
}
8.從ASP.NET Core DI框架注入
Install-Package Mapster.DependencyInjection
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSingleton(GetAdapterConfig());
services.AddScoped<IMapper, ServiceMapper>();
}
private TypeAdapterConfig GetAdapterConfig()
{
var config = new TypeAdapterConfig();
config.NewConfig<ClassA, ClassB>()
.Map(b => b.Name, a => $"{a.Id}_{a.Price}");
config.NewConfig<ClassB, ClassC>()
.Ignore(c => c.Name)
.Map(c => c.Id, b => b.Id + 2);
return config;
}
9.注入使用
Controller
public HomeController(IMapper mapper)
{
_mapper = mapper;
}
public string Index()
{
var classA = new ClassA()
{
Id = 1,
Name = "Test",
Price = 12.34m
};
var classB = _mapper.Map<ClassB>(classA);
return JsonConvert.SerializeObject(classB);
}
public string Index2()
{
var classA = new ClassB()
{
Id = 1,
Name = "Test",
Price = 12.34m
};
var classC = _mapper.Map<ClassC>(classA);
return JsonConvert.SerializeObject(classC);
}
官方也有提供常見幾個套件的效能比較,跟主流的AutoMapper相比不差
Method | Mean | StdDev | Error | Gen 0 | Gen 1 | Gen 2 | Allocated |
---|---|---|---|---|---|---|---|
'Mapster 5.0.0' | 141.84 ms | 0.931 ms | 1.408 ms | 31250.0000 | - | - | 125.12 MB |
'Mapster 5.0.0 (Roslyn)' | 60.48 ms | 1.186 ms | 1.993 ms | 31222.2222 | - | - | 125.12 MB |
'Mapster 5.0.0 (FEC)' | 58.17 ms | 0.231 ms | 0.442 ms | 29714.2857 | - | - | 119.02 MB |
'Mapster 5.0.0 (Codegen)' | 51.56 ms | 0.312 ms | 0.524 ms | 31200.0000 | - | - | 125.12 MB |
'ExpressMapper 1.9.1' | 299.05 ms | 2.081 ms | 3.146 ms | 60000.0000 | - | - | 241.85 MB |
'AutoMapper 9.0.0' | 708.06 ms | 3.398 ms | 5.137 ms | 91000.0000 | - | - | 364.69 MB |
GitHub https://github.com/MapsterMapper/Mapster
Sample Code https://github.com/ianChen806/MapsterSample/tree/master