型Aを継承していて、かつインターフェースIBを実装しているような型だけを引数に受け付けたい。
以下、型A=System.Web.UI.Page、インターフェースB=IHogePage とする。
方法1.cs
// Page または IHogePage を引数にして中で型チェック。不正なら例外を投げる。
public void Hoge(Page page)
{
var hoge = page as IHogePage;
if (hoge == null) throw new ArgumentException();
page.Controls.Add(new TextBox { ID = hoge.HogeMember });
}
public interface IHogePage
{
string HogeMember { get; }
}
- メリット
- .NET的に素直?
- デメリット
-
IHogePage
を実装していなければいけないことがシグネチャから伝わらない -
IHogePage
を実装していない型のインスタンスを渡してしまっても実行時までエラーにならない
-
方法2.cs
// Page を継承していて IHogePage を実装する抽象クラスを作る
public void Hoge(HogePage page)
{
page.Controls.Add(new TextBox { ID = page.HogeMember });
}
public interface IHogePage
{
string HogeMember { get; }
}
public abstract class HogePage : Page, IHogePage
{
public abstract string HogeMember { get; }
}
- メリット
- 型安全になる
- デメリット
-
HogePage
以外を継承したいクラスに対応できない
-
方法3.cs
// ジェネリックメソッドにして型制約で 2 つの型を強制させる
public void Hoge<T>(T t)
where T : Page, IHogePage
{
t.Controls.Add(new TextBox { ID = t.HogeMember });
}
public interface IHogePage
{
string HogeMember { get; }
}
- メリット
- 型安全かつ好きなクラスを継承してもらえる
- デメリット
- ジェネリック本来の使い方と違う気が
方法3がベストな気がしていますが、本来ジェネリックである必要はないので気持ち悪さが残るところ。