|
|
連載:[完全版]究極のC#プログラミング
Chapter6 ラムダ式(前編)
川俣 晶
2009/10/19 |
|
|
6.6 デリゲートの共変性と反変性
これはラムダ式に限定されない話題だが、関連性があるので取り上げておく。
次ページのリスト6.8のソースコードは、Visual Studio .NET 2003(以下、VS.NET 2003)ではコンパイルエラーになるが、Visual Studio 2008(以下、VS 2008)ではコンパイルできる。
using System;
abstract class Person
{
public abstract void SayMyName();
}
class StringNamePerson : Person
{
string name;
public override void SayMyName()
{
Console.WriteLine("私が{0}です。", name);
}
public StringNamePerson(string name)
{
this.name = name;
}
}
delegate Person PersonCreator();
class Program
{
static StringNamePerson Target()
{
return new StringNamePerson("L");
}
static void Main(string[] args)
{
// オブジェクトを作成する方法を取得する
// (VS.NET 2003ではエラーになる)
PersonCreator creator = new PersonCreator(Target);
// 実際にオブジェクトを作成して使用する
creator().SayMyName(); // 出力:私がLです。
}
}
|
|
リスト6.8 デリゲートの共変性の例(VS.NET 2003ではコンパイルエラーになる) |
ここで、「new PersonCreator(Target);」というデリゲートの作成が問題になる。PersonCreatorデリゲートの戻り値の型はPerson型であるのに対して、メソッドTargetの戻り値の型はStringNamePerson型であるためだ。
VS.NET 2003は、これを型の不一致と見なして「メソッド 'Program.Target()' はデリゲート型 'Person PersonCreator()' と一致しません。」というエラーとする。しかし、StringNamePersonクラスはPersonクラスを継承しているため、Person型と見なして受け入れてもうまく機能する。VS 2005では、そのようにして受け入れるようになっている。これを「デリゲートの共変性」という。
ちなみに、
PersonCreator creator = new PersonCreator(Target);
|
|
という式は、VS.NET 2003でも構文エラーにしないためにこのように記述しているが、VS 2008では、
PersonCreator creator = Target;
|
|
でかまわない。
以上は戻り値の型の場合だが、引数の型は逆に、より強い型を指定されたメソッドを、より弱い型のデリゲートで受け付ける拡張が行われている。これを「デリゲートの反変性」という。趣旨は同様なので、実例となるサンプルコードのみリスト6.9として掲載しておく。
using System;
abstract class Person
{
public abstract void SayMyName();
}
class StringNamePerson : Person
{
string name;
public override void SayMyName()
{
Console.WriteLine("私が{0}です。", name);
}
public StringNamePerson(string name)
{
this.name = name;
}
}
delegate void SayObjectName(StringNamePerson p);
class Program
{
static void Target(Person p)
{
p.SayMyName();
}
static void Main(string[] args)
{
// VS.NET 2003ではエラーになる
SayObjectName say = new SayObjectName(Target);
say(new StringNamePerson("L")); // 出力:私がLです。
}
}
|
|
リスト6.9 デリゲートの反変性の例(VS.NET 2003ではコンパイルエラーになる) |
ちなみに、
SayObjectName say = new SayObjectName(Target);
|
|
という式は、先ほどと同様に2008では、
SayObjectName say = Target;
|
|
でかまわない。
Insider.NET 記事ランキング
本日
月間