概要
2023年11月に.NET 8とC# 12がリリースされました。
この投稿では、.NET 8でLINQに追加された「ToDictionaryの複数のオーバーロード」について紹介します。
昨年リリースの「.NET 7」で追加されたメソッドは、こちらをどうぞ!
一昨年リリースの「.NET 6」で追加されたメソッドはこちらをどうぞ!
ToDictionaryメソッドとは?
ToDictionaryメソッドは、次のコードのようにIEnumerable<T>から、Dictionary<TKey, TSource>を作成するメソッドです。
public readonly record struct Skill(int Id, string Name);
List<Skill> skills = [
new Skill(
Id: 0,
Name: "ファイアー"
),
new Skill(
Id: 1,
Name: "エルファイアー"
),
new Skill(
Id: 2,
Name: "サンダー"
),
new Skill(
Id: 3,
Name: "サンダーストーム"
),
new Skill(
Id: 4,
Name: "エイルカリバー"
)
];
var skillNameDictionary = skills.ToDictionary(it => it.Id, it => it.Name);
Console.WriteLine(skillNameDictionary[0]); // ファイアー
Console.WriteLine(skillNameDictionary[1]); // エルファイアー
.NET 7までは、次の4種のオーバーロードがありました。
- ToDictionary<TSource,TKey,TElement>(IEnumerable<TSource>, Func<TSource,TKey>, Func<TSource,TElement>)
- ToDictionary<TSource,TKey,TElement>(IEnumerable<TSource>, Func<TSource,TKey>, Func<TSource,TElement>, IEqualityComparer<TKey>)
- ToDictionary<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>)
- ToDictionary<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>, IEqualityComparer<TKey>)
一見複雑そうですが、次の組み合わせで4パターンとなります。
- キーセレクターのみ(Func<TSource,TKey>)を引数に取る or キーセレクター(Func<TSource,TKey>)とバリューセレクター(Func<TSource,TElement>)両方を引数に取る
- IEqualityComparer<TKey>を引数に取る or 引数に取らない
既存のオーバーロードは、すべてIEnumerable<TSource>の拡張メソッドであることに注目してください。
新たにToDictionaryメソッドに追加されたオーバーロードは?
新たにToDictionaryメソッドに追加されたオーバーロードは、次の4個です。
- ToDictionary<TKey,TValue>(IEnumerable<KeyValuePair<TKey,TValue>>)
- ToDictionary<TKey,TValue>(IEnumerable<KeyValuePair<TKey,TValue>>, IEqualityComparer<TKey>)
- ToDictionary<TKey,TValue>(IEnumerable<ValueTuple<TKey,TValue>>)
- ToDictionary<TKey,TValue>(IEnumerable<ValueTuple<TKey,TValue>>, IEqualityComparer<TKey>)
既存のオーバーロードは、すべてIEnumerable<TSource>の拡張メソッドでした。新たに追加されたオーバーロードは
IEnumerable<KeyValuePair<TKey,TValue>>
または
IEnumerable<ValueTuple<TKey,TValue>>
の拡張メソッドです。
次の組み合わせで4パターンとなります。
- IEnumerable<KeyValuePair<TKey,TValue>>の拡張メソッド or IEnumerable<ValueTuple<TKey,TValue>>の拡張メソッド
- IEqualityComparerを引数に取る or IEqualityComparerを引数に取らない
どんなふうに使う?何が嬉しい?
新たに加わったオーバーロードにより、IEnumerable<KeyValuePair<TKey,TValue>>またはIEnumerable<ValueTuple<TKey,TValue>>に対して、
「ToDictionary(it => it.Key, it => it.Value)
」のような記述を、
「ToDictionary()
」と簡潔に記述できるようになります。
例えば、Dictionary<TKey, TSource>は、IEnumerable<KeyValuePair<TKey,TValue>>を実装しています。そのため、次のようにDictionary<TKey, TSource>をフィルタリングして、Dictionary<TKey, TSource>を再構成するコードが簡潔にかけます。
// TODO もっと.NET 8っぽく書く
List<Skill> skills = [
new Skill(
Id: 0,
Name: "ファイアー"
),
/* 略 */
];
var skillNameDictionary = skills.ToDictionary(it => it.Id, it => it.Name);
var onlyFireSkillNameDictonary = skillNameDictionary
.Where(it => it.Value.Name.Contains("ファイアー"))
.ToDictionary(); // .NET 7までは、「.ToDictionary(it => it.Key, it => it.Value)」ってやってた
なお、新たに追加されたオーバーロードも既存のオーバーロードと同様、キーの重複に対してArgumentExceptionをスローすることに注意してください
まとめ
.NET 8でLINQに追加された「ToDictionaryの複数のオーバーロード」について紹介しました。
新たに加わったオーバーロードにより、IEnumerable<KeyValuePair<TKey,TValue>>またはIEnumerable<ValueTuple<TKey,TValue>>で、「ToDictionary(it => it.Key, it => it.Value)
」と記述をしていた箇所を「ToDictionary()
」と簡潔に記述できるよになりました。
個人的には、.NET 8でのLINQの追加は、「そんなに自分が活用する機会は多くないかもな〜」とも思いますが、今後の進化も楽しみです。