normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

ジェネリックスを用いた汎用クラスの定義方法

今回の記事はC#プログラミングの基礎な気もしますが、気にせずに書く。気さくな突っ込み募集(いいタイトルを思いつかなかったので、そこも突っ込み募集)。
いやぁ、ASP.NET MVCを弄っていて、ViewPageクラスがふと気になったんですよ。何が気になったかと言うと、

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

こういうのとか

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<BtoCDemo.Models.Product>" %>

こういうの。

同じクラスにもかかわらず、ジェネリックス使って汎用化してます。「どうやって汎用化をしているんだろうなぁ〜?」と思うのが人情というもの。実際のViewPageクラスを参考にして、WrapperModelというクラスを作って検証してみました。結果、大体以下の要領で汎用化してました。

class WrapperModel
{
    protected object _model;

    public object Model
    {
        get { return _model; }
        set {
            _model = value;
        }
    }
}

//同一名のクラスを継承し、ジェネリックスクラスを再定義している!
class WrapperModel<TModel> : WrapperModel where TModel : class
{
    //※注 ここでnew!?
    public new TModel Model
    {
        get { return (TModel)base._model; }
        set {
            base._model = value;
        }
    }
}

要点としては以下

  1. 以下の情報を持つ元クラス(この例ではWrapperModel)を定義する。
    • オブジェクト型のModelプロパティを定義
    • protected object型のメンバ変数を定義
  2. 汎用化したジェネリックスクラスを定義
    • TModel型パラメータを用いて汎用化。ただし、class条件をつけて型パラメータに代入できる値はクラスだけにする。
    • TModel型のModelプロパティを再定義する。この際に"new"修飾子をつける必要が有る

コーディングの仕方はわかったのですが、以下が良くわからない疑問ポイント。Reflectorでも使って内部見た方が良さそうかな。

  • ジェネッリクスクラス側のModelプロパティで、何故new修飾子が必要か?
    • ⇒ 意図的に親クラスのプロパティを隠す(上書き?)したかったらnewをつけろと警告されてた…orz
      • ⇒ 同じ名前のプロパティであると、型名が継承じゃなく全く異なる場合でも、newさえつければ上書きできるですね・・・。しらなかった。
  • ジェネリックスクラス・非ジェネリックスクラス共に同じ名前で定義されているが、内部的にどの様に区別されているか?