Out of Memory

本ブログは更新を停止しました。Aerieをよろしくお願いいたします。

目次

Blog 利用状況

ニュース

2009年3月31日
更新を停止しました。引き続きAerieを御愛顧くださいませ。
2009年2月3日
原則としてコメント受付を停止しました。コメントはAerieまでお願いいたします。
詳細は2月3日のエントリをご覧ください。
2008年7月1日
Microsoft MVP for Developer Tools - Visual C++ を再受賞しました。
2008年2月某日
MVPアワードがVisual C++に変更になりました。
2007年10月23日
blogタイトルを変更しました。
2007年7月1日
Microsoft MVP for Windows - SDKを受賞しました!
2007年6月20日
スキル「ニュース欄ハック」を覚えた!
2006年12月14日
記念すべき初エントリ
2006年12月3日
わんくま同盟に加盟しました。

カレンダー

中の人

αετο? / aetos / あえとす

シャノン? 誰それ。

顔写真

埼玉を馬鹿にする奴は俺が許さん。

基本的に知ったかぶり。興味を持った技術に手を出して、ちょっと齧りはするものの、それを応用して何か形にするまでは及ばずに飽きて放り出す人。

書庫

日記カテゴリ

拡張メソッドなら、this == null でもいい。

拡張メソッドの実体は、インスタンスをthis引数にとる静的メソッドです。
この場合、this引数にnullを渡せない理由はありません。
拡張メソッドでなければ、即座に NullReferenceException が飛んで「ガッ」とやられるところですが、拡張メソッドでは、少なくともメソッドを呼び出すところまではできます(メソッド内で例外が飛ばないかどうかは仕様による)。

投稿日時 : 2008年1月17日 16:00

Feedback

# re: 拡張メソッドなら、this == null でもいい。 2008/01/17 16:12 NyaRuRu

>拡張メソッドでなければ、即座に NullReferenceException が飛んで「ガッ」とやられるところですが

これは callvirt でインスタンスメソッドを呼んだ場合,CLR がそのように振る舞うという話です.
call でインスタンスメソッドを呼んだ場合,CLR は this が null かどうかをチェックしません.

# re: 拡張メソッドなら、this == null でもいい。 2008/01/17 17:00 シャノン

ふーむ。
C# で call 命令を生成する方法はあるんですかね?

# re: 拡張メソッドなら、this == null でもいい。 2008/01/17 17:01 シャノン

あ、VB.NET でもいいや。
C++/CLI は微妙。C++ はもともと、メンバ変数にアクセスしなければ大丈夫だし(規格上の保証は無いだろうけど)。

# re: 拡張メソッドなら、this == null でもいい。 2008/01/17 17:32 NyaRuRu

とりあえず以下のようなコードで this が null になります.

using System;

public class Foo
{
public string GetStr(int i)
{
Console.WriteLine("this is null? -> {0}", this == null);
return i.ToString();
}
}
static class Program
{
static void Main(string[] args)
{
Func<Foo, int, string> f =
Delegate.CreateDelegate(
typeof(Func<Foo, int, string>),
typeof(Foo).GetMethod("GetStr"))
as Func<Foo, int, string>;

Console.WriteLine(f(null, 1));
}
}

>C++ はもともと、メンバ変数にアクセスしなければ大丈夫だし

私の場合,.NET 言語を見るときは「生成された IL が動くかどうか」に興味があって,言語内で閉じた美しさとか完備性にはあまり興味がなかったりします.
まあ Foo というクラスの int を引数にとって string を返すメソッドが,
Func<Foo, int, string> にバインドできる CLR 型システムは,それなりに綺麗だとは思いますがね.

# re: 拡張メソッドなら、this == null でもいい。 2008/01/17 18:48 シャノン

むー。
俺としては、呼び出し側の視点として、instance.Method(); と書くときの instance が null であってもよい、ということに対する驚きを書いてみたつもり。
呼び出される側にとっても this == null の場合があるというのは、(拡張メソッドである場合を除いては)驚きでもなんでもなく、むしろ迷惑というか。

# こういうサンプルを提示されることが迷惑、ではないです。
# GetStrにとって、こういう呼ばれ方をすることが迷惑、ということ。

まさか、そういう呼び方が可能であるから、あらゆるインスタンスメソッドは this == null である可能性を考慮しておけ、というわけでは当然無いだろうし。

> 私の場合,.NET 言語を見るときは「生成された IL が動くかどうか」に興味があって,言語内で閉じた美しさとか完備性にはあまり興味がなかったりします.

俺は正反対で、(今のところはまだ)言語にしか興味がありません。
それがどういう IL になってどう動くかは、敢えて意識しないようにしています。
だから Reflection.Emit なんか見たくもありません。
「インサイドIL 日本語版」とかいう本が出たら、一転して IL にどっぷりはまりそうな気もしますが。

# re: 拡張メソッドなら、this == null でもいい。 2008/01/17 20:33 NyaRuRu

>GetStrにとって、こういう呼ばれ方をすることが迷惑、ということ。

確かに迷惑ではありますが,必要な場所では NullReferenceException が発生するわけで,C/C++ の未初期化変数へのアクセスのような悪性の問題ではないと思っています.

ちなみに,個人的な意見ですが,CLI が「this が this のように振る舞う」ということ自体を属性的に定義していなかったのは失敗だと思っています.this は元々特殊引数で,他のメソッド引数を this のように振る舞わせる仕組みは CLI には用意されていません.
このため,拡張メソッドのように「this の様に見える第一引数」のセマンティクスと,従来の this のセマンティクスとが,微妙に異なってしまっています.
例えば値型に定義されたインスタンスメソッドを,拡張メソッドは再現できません.これは CLI 規格が,参照型と値型で this の扱いを変えるためです.拡張メソッドでは値型タイプの this の積み方をどうしても再現できません.
ByRef を利用した拡張メソッドをサポートする VisualBasic はでは,さらにややこしくなります.
VisualBasic では,C# でいうところの ref キーワードを書かないため,
instance.Method()
の instance が ref 渡しということが実際に可能です.そのため,
instanceA.Swap( instanceB )
のようなコードも書けてしまいます.
このあたりの問題については,以下の記事が詳しいです.
http://blogs.msdn.com/vbteam/archive/2007/01/18/extension-methods-part-3.aspx
http://blogs.msdn.com/sreekarc/archive/2007/04/25/extension-methods.aspx

# re: 拡張メソッドなら、this == null でもいい。 2008/01/18 11:38 シャノン

詳しいことは良くわかりませんけど、
> 他のメソッド引数を this のように振る舞わせる仕組みは CLI には用意されていません.
もしあったとしたら、C#にはなくてVBに用意される機能になりそうな気がします。なんとなく。

タイトル
名前
Url
コメント