稀に IList
型のデータを受け取ることがあります。ObservableCollection の CollectionChanged のイベントなどは、IList
で変更のあったデータのコレクションを返却します。
しかし、IList
から IList<T>
に変換する際は一工夫しないとダメです。その内容をメモ。
IList
to IList<T>
IList
と IList<T>
は単純に as 句で変換できそうなものですが、これがうまくいきません。
継承関係をよーく見てみよう。(IList
から IEnumerable<T>
に変換したいときも同じ)
C# 2.0 で追加されたジェネリック型に対応した IList<T>
と IList
は別々の派生になっており IEnumerable くらいしか互換性が無さそうです。
as 句だけだとうまく変換できない理由はわかったので、拡張メソッドで解決する例を示すことにします。
internal static class Extension { public static List<T> ToList<T>(this System.Collections.IList source) { return source?.Cast<T>().ToList() ?? new List<T>(); } public static T[] ToArray<T>(this System.Collections.IList source) { return source?.Cast<T>().ToArray() ?? Array.Empty<T>(); } }
こんな感じで変換します。
Samples.CollectionChanged += (sender, args) => { // OldItems が IList? 型 var list = args.OldItems?.ToList<Data>() ?? new (); list.ForEach(p => Debug.WriteLine(p)); };
この種の拡張メソッド定義は、独自のライブラリーなんかによく収録されたりすると思いますが、名前空間なしに定義するのも(当然)憚られたり、標準の名前空間を共有するのもややこしいと感じることがあったりする。
そういうときは、global using が役に立つことがあります。
global using ディレクティブ
拡張メソッドをまとめたようなライブラリーの名前空間 using 句をすべてのプログラムファイルに記述するのは、「わかりきっているため」冗長に感じることがあります。 そういうときは、思い切って global using を使うのもよいと思います。
わかりきっているような using は、今となっては得られる情報もすくないので、省略するような感じです。(たとえば、以下の using 句の並びは見慣れたものだと思います)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;
global using を利用する際は、using.cs
や imports.cs
ファイルなどプロジェクトごとに1つのファイルで実施するようにしましょう。やたらめったらに書くと混乱します。
個人的なシーンでは、毎回使うような独自のオリジナルライブラリーを持っていると、プロジェクトのたくさんのファイルに using を追加する必要があって面倒だったりします。
特に拡張メソッドを定義した名前空間なんかは、なるべく共有したいので、大きいプロジェクトでは global using 用のファイルを1つ生成しておきます。
global using System; global using System.Collections.Generic; global using System.Linq; global using System.Text; global using System.Threading.Tasks; // コメント global using MyLibrary.Extensions;
それほど難しい機能ではないですが、マナーやお作法として注意が必要な機能です。 どういったものか見ておきましょう。