C#

[C#] IEnumerableの一括キャスト

継承による親子関係がある2つのクラスT1/T2があったとき、IEnumerable<T1>をIEnumerable<T2>に変換する方法について。

なお、今回はIEnumerableインターフェースを実装しているListクラスを使ってサンプルコードを書いていきます。
 

わざわざ記事にしましたが、コレクション間でキャストしたいだけであれば、あれこれ考えず素直に、新しいコレクションに1つずつキャストして詰め直していけばよいのです。

class BaseClass
{
}

class SubClassA : BaseClass
{
}

void Main()
{
    List<BaseClass> baseItems = new List<BaseClass>()
    {
        new SubClassA() { Name = "なまえ1" },
        new SubClassA() { Name = "なまえ2" },
        new SubClassA() { Name = "なまえ3" },
    };


    //==== 基本クラスコレクションから派生クラスAコレクションにキャスト ====//
    List<SubClassA> castAItems = new List<SubClassA>();
    foreach (var item in baseItems)
    {
        castAItems.Add(item);
    }
}

 
でも、少し面倒ですね。そこで登場するのがCastメソッド。
一括変換する場合は、このメソッドを使うとすっきりと記述できます。

コレクションに積まれた基本クラス派生オブジェクトからSubClassBクラスのオブジェクトのみを抽出し、そのクラス特有の処理を一括で行いたい場合はこんな感じで実装すればOK。

    /// <summary>
    /// IEnumerableの一括キャスト検証クラス
    /// </summary>
    class IEnumerableCast
    {
        #region クラス
        /// <summary>
        /// 基本クラス
        /// </summary>
        class BaseClass
        {
            /// <summary>
            /// 名前
            /// </summary>
            public string Name { get; set; }
        }


        /// <summary>
        /// 派生クラスA
        /// </summary>
        class SubClassA : BaseClass
        {
            /// <summary>
            /// 派生クラスA特有のメソッド
            /// </summary>
            public void FuncA()
            {
                Console.WriteLine("A:{0}", Name);
            }
        }


        /// <summary>
        /// 派生クラスB
        /// </summary>
        class SubClassB : BaseClass
        {
            /// <summary>
            /// 派生クラスB特有のメソッド
            /// </summary>
            public void FuncB()
            {
                Console.WriteLine("B:{0}", Name);
            }
        }
        #endregion  // クラス





        #region フィールド
        /// <summary>
        /// BaseClassコレクション
        /// </summary>
        private List<BaseClass> baseItems = new List<BaseClass>()
        {
            new SubClassA() { Name = "なまえ1" },
            new SubClassB() { Name = "なまえ2" },
            new SubClassA() { Name = "なまえ3" },
            new SubClassA() { Name = "なまえ4" },
            new SubClassB() { Name = "なまえ5" },
        };
        #endregion  // フィールド





        #region メソッド
        /// <summary>
        /// 検証用メソッド
        /// </summary>
        public void Main()
        {
            //==== 派生クラスAを抽出 ====//
            // こっちは個別にキャストしていく場合。
            //
            IEnumerable<BaseClass> subAItems = baseItems.Where(x => x.GetType() == typeof(SubClassA));
            if (subAItems.Any())
            {
                //-==- 派生クラスAが存在する -==-//
                List<SubClassA> castAItems = new List<SubClassA>();
                foreach (var item in subAItems)
                {
                    castAItems.Add((SubClassA)item);
                }


                //==== 派生クラスAのメソッドを実行 ====//
                foreach (var item in castAItems)
                {
                    item.FuncA();
                }
            }


            //==== 派生クラスBを抽出 ====//
            // 一括キャストする場合。
            //
            IEnumerable<BaseClass> subBItems = baseItems.Where(x => x.GetType() == typeof(SubClassB));
            if (subBItems.Any())
            {
                //-==- 派生クラスBが存在する -==-//

                //==== 派生クラスBコレクションに一括キャスト ====//
                IEnumerable<SubClassB> castBItems = subBItems.Cast<SubClassB>();


                //==== 派生クラスBのメソッドを実行 ====//
                foreach (var item in castBItems)
                {
                    item.FuncB();
                }
            }
        }
        #endregion  // メソッド
    }

 
こんなにダラダラと書くほどの内容でもないのですが、まぁ・・・。
 
 

-C#
-