プログラム内のオブジェクトを外部に転送するためにDTO (Data Transfer Object) を使うことがありますが、C#であればAutoMapperという便利なライブラリがあります。
これまでAutoMapperでDTOに詰め替えする際、DTOクラスはプロパティは①getアクセサーのみでコンストラクタで代入するのが一般的でした。もしくは簡単に②setアクセサーを設定する方法もありました。
それぞれの方法の特徴は以下の通りです。
①getアクセサーのみでコンストラクタで代入
- DTO生成後に意図せず値を書き換えられない(良いこと)
- コンストラクタを作るのが面倒
②setアクセサーを設定する
- DTO生成後に値を書き換えられてしまう
- コンストラクタを作らなくていいので楽
それぞれ良いところと悪いところがありましたが、C#9.0 の新機能に initアクセサーが登場したことでこの2つのいいとこどりができるようになりました。特徴をまとめておきます。
③initアクセサーを使う
- DTO生成後に値を書き換えられない(良いこと)
- コンストラクタが不要
参考のため各方法のサンプルコードを載せておきます。
サンプルコード
①getアクセサーのみでコンストラクタで代入
using AutoMapper;
using System;
namespace AutoMapperTest
{
class Program
{
static void Main(string[] args)
{
var config = new MapperConfiguration(cfg => cfg.CreateMap<Item, ItemDto>());
var mapper = config.CreateMapper();
var item = new Item(1, "商品1", 100);
ItemDto itemDto = mapper.Map<ItemDto>(item);
Console.WriteLine("Item:");
Console.WriteLine($"Id: {item.Id}, Name: {item.Name}, Price: {item.Price}");
Console.WriteLine("ItemDto:");
Console.WriteLine($"Id: {itemDto.Id}, Name: {itemDto.Name}, Price: {itemDto.Price}");
}
}
class Item
{
public Item(int id, string name, int price)
{
Id = id;
Name = name;
Price = price;
}
public int Id { get; }
public string Name { get; private set; }
public int Price { get; private set; }
}
class ItemDto
{
public ItemDto(Item item) : this(item.Id, item.Name, item.Price)
{
}
public ItemDto(int id, string name, int price)
{
Id = id;
Name = name;
Price = price;
}
public int Id { get; }
public string Name { get; }
public int Price { get; }
}
}
②setアクセサーを設定する
using AutoMapper;
using System;
namespace AutoMapperTest
{
class Program
{
static void Main(string[] args)
{
var config = new MapperConfiguration(cfg => cfg.CreateMap<Item, ItemDto>());
var mapper = config.CreateMapper();
var item = new Item(1, "商品1", 100);
ItemDto itemDto = mapper.Map<ItemDto>(item);
Console.WriteLine("Item:");
Console.WriteLine($"Id: {item.Id}, Name: {item.Name}, Price: {item.Price}");
Console.WriteLine("ItemDto:");
Console.WriteLine($"Id: {itemDto.Id}, Name: {itemDto.Name}, Price: {itemDto.Price}");
}
}
class Item
{
public Item(int id, string name, int price)
{
Id = id;
Name = name;
Price = price;
}
public int Id { get; }
public string Name { get; private set; }
public int Price { get; private set; }
}
class ItemDto
{
public int Id { get; set; }
public string Name { get; set; }
public int Price { get; set; }
}
}
③initアクセサーを使う
using AutoMapper;
using System;
namespace AutoMapperTest
{
class Program
{
static void Main(string[] args)
{
var config = new MapperConfiguration(cfg => cfg.CreateMap<Item, ItemDto>());
var mapper = config.CreateMapper();
var item = new Item(1, "商品1", 100);
ItemDto itemDto = mapper.Map<ItemDto>(item);
Console.WriteLine("Item:");
Console.WriteLine($"Id: {item.Id}, Name: {item.Name}, Price: {item.Price}");
Console.WriteLine("ItemDto:");
Console.WriteLine($"Id: {itemDto.Id}, Name: {itemDto.Name}, Price: {itemDto.Price}");
}
}
class Item
{
public Item(int id, string name, int price)
{
Id = id;
Name = name;
Price = price;
}
public int Id { get; }
public string Name { get; private set; }
public int Price { get; private set; }
}
class ItemDto
{
public int Id { get; init; }
public string Name { get; init; }
public int Price { get; init; }
}
}