<?xml version="1.0" encoding="UTF-8" ?> <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>.NET Framework 2.x</title><link>http://blogs.wankuma.com/jitta/category/351.aspx</link><description>.NET Framework 2.x 関係</description><managingEditor>はなおか じった</managingEditor><dc:language>ja-JP</dc:language><generator>.Text Version 0.95.2004.102</generator><item><dc:creator>はなおか じった</dc:creator><title>WinSNMP をラップ</title><link>http://blogs.wankuma.com/jitta/archive/2011/06/24/200239.aspx</link><pubDate>Fri, 24 Jun 2011 22:06:00 GMT</pubDate><guid>http://blogs.wankuma.com/jitta/archive/2011/06/24/200239.aspx</guid><wfw:comment>http://blogs.wankuma.com/jitta/comments/200239.aspx</wfw:comment><comments>http://blogs.wankuma.com/jitta/archive/2011/06/24/200239.aspx#Feedback</comments><slash:comments>459</slash:comments><wfw:commentRss>http://blogs.wankuma.com/jitta/comments/commentRss/200239.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/jitta/services/trackbacks/200239.aspx</trackback:ping><description>&lt;p&gt;　ちょっと使いたかったのだが、探すと無かったので、作ってみた。&lt;/p&gt;
&lt;iframe title ="Preview" scrolling="no" marginheight="0" marginwidth="0" frameborder="0" style="width:98px;height:115px;padding:0;background-color:#fcfcfc;" src="https://skydrive.live.com/embedicon.aspx/.Public/WinSNMP.NET.zip?cid=4d4a162589943324&amp;sc=documents"&gt;&lt;/iframe&gt;
&lt;p&gt;　使う場合は、自己責任で。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/jitta/aggbug/200239.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>はなおか じった</dc:creator><title>メモ：XmlSerializer で、名前空間の出力を抑制する</title><link>http://blogs.wankuma.com/jitta/archive/2011/01/19/196546.aspx</link><pubDate>Wed, 19 Jan 2011 22:02:00 GMT</pubDate><guid>http://blogs.wankuma.com/jitta/archive/2011/01/19/196546.aspx</guid><wfw:comment>http://blogs.wankuma.com/jitta/comments/196546.aspx</wfw:comment><comments>http://blogs.wankuma.com/jitta/archive/2011/01/19/196546.aspx#Feedback</comments><slash:comments>73</slash:comments><wfw:commentRss>http://blogs.wankuma.com/jitta/comments/commentRss/196546.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/jitta/services/trackbacks/196546.aspx</trackback:ping><description>&lt;p class="p"&gt;&lt;code&gt;XmlSerializer.Serialize&lt;/code&gt; メソッドを使うと、ルート要素に名前空間が追加されます。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;?xml version="1.0"?&amp;gt;
&amp;lt;root &lt;span style="color:red;"&gt;xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;&amp;gt;
&amp;lt;/root&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p class="p"&gt;これを、抑制する方法。&lt;/p&gt;
&lt;p class="p"&gt;オーバーロードされた &lt;code&gt;Serialize&lt;/code&gt; メソッドに、&lt;code&gt;XmlSerializerNamespaces&lt;/code&gt; クラスのインスタンスを受け取るものがあります。ここに &lt;code&gt;null&lt;/code&gt; を指定したり、何も追加していないインスタンスを指定しても、やはり規定の名前空間が出力されます。ステップインしてコードを見ると、&lt;code&gt;null&lt;/code&gt; や &lt;code&gt;Count&lt;/code&gt; が0の時は、規定の名前空間に置き換えるというコードが書かれていました。&lt;/p&gt;
&lt;p class="p"&gt;ところが、&lt;code&gt;XmlSerializerNamespaces&lt;/code&gt; クラスへの名前空間の追加については、なんのチェックもされていないようです（未確認）。ということで、空文字列の名前空間を追加したインスタンスを指定してあげます。&lt;/p&gt;
&lt;pre class="code"&gt;&lt;code&gt;
&lt;span style="color:red;"&gt;XmlSerializerNamespaces ns = new XmlSerializerNamespaces();&lt;/span&gt;
// null または、個数が0個だと、規定の名前空間が追加されるので、1個にする。
&lt;span style="color:red;"&gt;ns.Add("", "");&lt;/span&gt;
XmlSerializer xs = new XmlSerializer(typeof(&lt;span style="font-style:italic;"&gt;TYPE&lt;/span&gt;));
using (StreamWriter writer = new StreamWriter(&lt;span style="font-style:italic;"&gt;fileName&lt;/span&gt;, false)) {
    xs.Serialize(writer, &lt;span style="font-style:italic;"&gt;object&lt;/span&gt;&lt;span style="color:red;"&gt;, ns&lt;/span&gt;);
    writer.Flush();
    writer.Close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;?xml version="1.0"?&amp;gt;
&amp;lt;root&amp;gt;
&amp;lt;/root&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p class="p"&gt;「&lt;code&gt;xmlns:xsd="http://www.w3.org/2001/XMLSchema"&lt;/code&gt;」を、「&lt;code&gt;xmlns="http://www.w3.org/2001/XMLSchema"&lt;/code&gt;」の様に出力させたいと思って、「&lt;code&gt;ns.Add("", "http://www.w3.org/2001/XMLSchema");&lt;/code&gt;」としたら、なんにも出力されなくなったので気がついたのでした。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/jitta/aggbug/196546.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>はなおか じった</dc:creator><title>ボックス化／ボックス化解除って、なに？</title><link>http://blogs.wankuma.com/jitta/archive/2009/06/03/174072.aspx</link><pubDate>Wed, 03 Jun 2009 22:35:00 GMT</pubDate><guid>http://blogs.wankuma.com/jitta/archive/2009/06/03/174072.aspx</guid><wfw:comment>http://blogs.wankuma.com/jitta/comments/174072.aspx</wfw:comment><comments>http://blogs.wankuma.com/jitta/archive/2009/06/03/174072.aspx#Feedback</comments><slash:comments>1017</slash:comments><wfw:commentRss>http://blogs.wankuma.com/jitta/comments/commentRss/174072.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/jitta/services/trackbacks/174072.aspx</trackback:ping><description>&lt;p class="p"&gt;先のエントリで言及したけど、意識したことがなかったので、意識してみるエントリー。&lt;/p&gt;
&lt;p class="p"&gt;Visual C# 2008 をインストールすると、インストールしたディレクトリの下（C:\Program Files\Microsoft Visual Studio 9.0\VC#\Specifications\1041）に、Word 形式の言語仕様があります。まず、これに尋ねます。&lt;/p&gt;
&lt;blockquote&gt;&lt;p class="quoteSource"&gt;『C# 言語仕様 Ver.3.0』「4.3 ボックス化とボックス化解除」より：&lt;/p&gt;
&lt;p&gt;ボックス化とボックス化解除は、C# の型システムの中心的な概念です。これは、&lt;span style="font-style:italic;"&gt;value-type&lt;/span&gt; のすべての値と &lt;code&gt;object&lt;/code&gt; 型間の変換を可能にするため、&lt;span style="font-style:italic;"&gt;value-types&lt;/span&gt; と &lt;span style="font-style:italic;"&gt;reference-types&lt;/span&gt; との橋渡しの役目を果たします。ボックス化とボックス化解除の機能により、型システムを統一的に見ることができるようになり、すべての型の値を最終的にオブジェクトとして扱うことができます。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="p"&gt;なるほど。&lt;q&gt;中心的な概念&lt;/q&gt;なのだそうです。うむむ。知らなかった。。。&lt;/p&gt;
&lt;p class="p"&gt;C# では、object 型は、全ての型の派生元であるとされています。派生元への変換は、暗黙の内に行えます。全ての型の派生元であるが故に、int や double などの値型からも暗黙の内に変換できなければなりません。この、値型から参照型への変換をしているのが、ボックス化、ってわけですね。&lt;/p&gt;
&lt;p class="p"&gt;何が行われるかについては、「4.3.1 ボックス化変換」に書いてあります。オブジェクト インスタンスの割り当てと、値のコピーが行われます。値のコピーが行われます？値のコピーですって？！&lt;/p&gt;
&lt;p class="p"&gt;はい、元のものとは別の、コピーされたものが作られます。コピーされるということは、コピーを書き換えても、オリジナルは書き換わらないということです。&lt;/p&gt;
&lt;p class="p"&gt;ではこれ、どういうところで問題になるのでしょう？&lt;/p&gt;
&lt;br&gt;
&lt;p class="p"&gt;と、、、思いつかないので（意識したことがないのだから、当たり前ですね）、ボックス化の問題ではないが、値型が関係する問題を紹介。&lt;/p&gt;
&lt;p class="p"&gt;Windows アプリケーションを作ります。&lt;code&gt;System.Windows.Forms.Form&lt;/code&gt; クラスです。フォームの位置は、&lt;code&gt;Forms.Location&lt;/code&gt; プロパティで参照できます。Location は、&lt;code&gt;System.Drawing.Point&lt;/code&gt; を返します。この中には、X 座標と Y 座標が入っています。では、次のようなコードで、フォームの位置を変えることができるでしょうか。&lt;/p&gt;
&lt;pre class="code"&gt;&lt;code&gt;
... 省略して、何かのメソッドの中 ...
    form1.Location.X += 100;     // 位置を右へ100ずらす
... 後ろも省略 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p class="p"&gt;わざわざ「問題を紹介」といっているのだから、変えることはできない、というのが正解です。なぜでしょう？&lt;/p&gt;
&lt;p class="p"&gt;プロパティは、アクセス メソッドを扱いやすくしたものです。メソッドに分解すると、先のコードは、次のコードのようになります。&lt;/p&gt;
&lt;pre class="code"&gt;&lt;code&gt;
... 省略して、何かのメソッドの中 ...
    System.Drawing.Point loc = form1.GetLocation();
    loc.X += 100;
... 後ろも省略 ...
... おそらく、Form.GetLocation() は、次のように実装されている ...
Point GetLocation()
{
    return this.location;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p class="p"&gt;ここで、Point が値型であることが重要です。Point は値型なので、GetLocation が返す値は、呼び出し元へコピーされます。コピーなので、いくら loc の値を変化させても、Form が持っている location の値は変化しません。変化させるためには、値型のプロパティそのものを書き換える必要があります。&lt;/p&gt;
&lt;pre class="code"&gt;&lt;code&gt;
... 省略して、何かのメソッドの中 ...
    Point loc = form1.Location;
    loc.X += 100;               // ここでは変化しない
    form1.Location = loc;       // ここで変わる
    loc.X -= 100;               // セッターでもコピーするので、これは変わらない
... 後ろも省略 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p class="p"&gt;これは、プロパティへのアクセスで値型の値渡しが行われ、値がコピーされることにより発生します。繰り返しますが、この例はボックス化による問題ではありません。しかし、ボックス化では、オブジェクト インスタンスの割り当てと、値のコピーが行われるため、ボックス化したときに元の値型変数が持つ値にアクセスすることはできなくなります。そのため、同じように、「値を変更したのに、変わってない」という問題が発生するでしょう。&lt;/p&gt;
&lt;br&gt;
&lt;br&gt;
&lt;p class="p"&gt;で、ボックス化が、どういうときに問題になるか。。。例えば、「変更することができる」というインターフェイスを作成します。このインターフェイスを実装する値型をつくります。「変更することができる」なので、変更をするメソッドを作ります。このとき、「変更する」メソッドを使う方は、インターフェイスからアクセスするでしょう。そうすると、値型をインターフェイスにキャストしたときに、実はボックス化が行われるので、「変更する」メソッドではボックス化された値型にアクセスすることになります。すると、これはボックス化の過程でコピーが行われているため、本来の値は変更されないことになります。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/jitta/aggbug/174072.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>はなおか じった</dc:creator><title>レーティングをお願いします。</title><link>http://blogs.wankuma.com/jitta/archive/2008/04/29/135731.aspx</link><pubDate>Tue, 29 Apr 2008 22:24:00 GMT</pubDate><guid>http://blogs.wankuma.com/jitta/archive/2008/04/29/135731.aspx</guid><wfw:comment>http://blogs.wankuma.com/jitta/comments/135731.aspx</wfw:comment><comments>http://blogs.wankuma.com/jitta/archive/2008/04/29/135731.aspx#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blogs.wankuma.com/jitta/comments/commentRss/135731.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/jitta/services/trackbacks/135731.aspx</trackback:ping><description>&lt;p&gt;&lt;a href="https://connect.microsoft.com/VisualStudioJapan/feedback/ViewFeedback.aspx?FeedbackID=331481" class="outerLink"&gt;VS2005 SP1をマージしたものを希望&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://connect.microsoft.com/VisualStudioJapan/feedback/ViewFeedback.aspx?FeedbackID=340947" class="outerLink"&gt;ライブラリや OS 機能の追加、変更、削除を RSS として配信して欲しい。&lt;/a&gt;&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/jitta/aggbug/135731.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>はなおか じった</dc:creator><title>VB 使うな、開発者なら。</title><link>http://blogs.wankuma.com/jitta/archive/2008/04/02/131353.aspx</link><pubDate>Wed, 02 Apr 2008 22:40:00 GMT</pubDate><guid>http://blogs.wankuma.com/jitta/archive/2008/04/02/131353.aspx</guid><wfw:comment>http://blogs.wankuma.com/jitta/comments/131353.aspx</wfw:comment><comments>http://blogs.wankuma.com/jitta/archive/2008/04/02/131353.aspx#Feedback</comments><slash:comments>13</slash:comments><wfw:commentRss>http://blogs.wankuma.com/jitta/comments/commentRss/131353.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/jitta/services/trackbacks/131353.aspx</trackback:ping><description>&lt;P class=p&gt;せめて、&lt;CODE&gt;Option Strict On&lt;/CODE&gt; にしてくれ。。。&lt;/P&gt;&lt;BR&gt;
&lt;BLOCKQUOTE&gt;
&lt;P class=quoteSource&gt;&lt;A class=outerLink title=→atmarkit.co.jp href="http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=44190&amp;amp;forum=7&amp;amp;6"&gt;件名：join でフリーズ&lt;/A&gt;（Insider.NET 会議室）より：&lt;/P&gt;
&lt;P&gt;コードはこんな感じです。&lt;/P&gt;&lt;PRE class=code&gt;&lt;CODE&gt;
class TestA
    dim obj as object
    public sub new()
        obj = new object()
    end sub
    public sub main()
        dim t as thread
        t = new system.threading.thread(new system.threading.threadstart(address of do))
        t.start()
        t.join()
    end sub
    public sub do()
        obj.start()
    end sub
enc class
&lt;/CODE&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P class=quoteSource&gt;&lt;A class=outerLink title=→atmarkit.co.jp href="http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=44208&amp;amp;forum=7&amp;amp;1"&gt;件名：Validatingでは&lt;/A&gt;（Insider.NET 会議室）より：&lt;/P&gt;&lt;PRE class=code&gt;&lt;CODE&gt;
Private Sub txtTCD_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles txtTCD.Validating
    Dim blnSUTI As Boolean
    Dim sb As New StringBuilder
    '*****
    If ActiveControl Is sender OrElse ActiveControl.CausesValidation = False OrElse sender.Text.Length = 0 Then
        Exit Sub
    End If
    '*** 入力ﾁｪｯｸ **************
    blnSUTI = Int32.TryParse(txtTCD.Text, mlngKEYTCD)
    If Trim(sender.Text).Length = 0 OrElse mlngKEYTCD = 0 Then
        MessageBox.Show("得意先を正しく入力して下さい", _
        Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        e.Cancel = True
        Exit Sub
    End If
    '*** ﾃﾞｰﾀ取得 **************
    Call mData()
    '*** ﾃﾞｰﾀ表示 **************
    Call mDisplay()
End Sub
'***
Private Sub 索引ﾎﾞﾀﾝｸﾘｯｸ
    Dim frmSAKUIN = New frmSAKUIN
    '*****
    If frmSAKUIN .ShowDialog = Windows.Forms.DialogResult.OK Then
        txtTCD.Text = frmSAKUIN .pTCD
        Call txtTCD_Validating(Nothing, Nothing)
    End If
    '*****
    frmAEIGS020.Dispose()
End Sub
&lt;/CODE&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;&lt;BR&gt;
&lt;P class=p&gt;勘弁してくれ。。。&lt;/P&gt;
&lt;P class=p&gt;上の方。obj は Object なので、start メソッドを持っていません。Strict Off にしているから実行時まで「start メソッドがあるかどうか」が延期され、、、って、おい！これ、なに？まさか、Thread.Start をしているとか？延々と自己呼び出しをやってんじゃないの？&amp;#8230;StackOverflow で落ちるか？何にしても、動かないコードを出して「これが動かない」といわれても、そりゃ、動きませんよ、と。&lt;/P&gt;
&lt;P class=p&gt;下の方。sender.Text って、そりゃないよ。。。きっと、&lt;CODE&gt;On Error Resume Next&lt;/CODE&gt; とかも指定してあるに違いない。Sender に Nothing にして呼び出して、その中のプロパティを呼ぼうとしたら、そりゃ、落ちるよ。&lt;/P&gt;&lt;BR&gt;
&lt;P class=p&gt;開発者なら。コンピュータと対話をする人なら。もっと、自分がコンピュータに対して何をお願いしようとしているか、自覚をしてください。&lt;/P&gt;&lt;img src ="http://blogs.wankuma.com/jitta/aggbug/131353.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>はなおか じった</dc:creator><title>Windows Form：警告の表示</title><link>http://blogs.wankuma.com/jitta/archive/2007/12/15/113113.aspx</link><pubDate>Sat, 15 Dec 2007 22:06:00 GMT</pubDate><guid>http://blogs.wankuma.com/jitta/archive/2007/12/15/113113.aspx</guid><wfw:comment>http://blogs.wankuma.com/jitta/comments/113113.aspx</wfw:comment><comments>http://blogs.wankuma.com/jitta/archive/2007/12/15/113113.aspx#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://blogs.wankuma.com/jitta/comments/commentRss/113113.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/jitta/services/trackbacks/113113.aspx</trackback:ping><description>&lt;blockquote&gt;&lt;p class="quoteSource"&gt;&lt;a href="http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=42520&amp;forum=7&amp;12" class="outerLink" title="→atmarkit.co.jp"&gt;件名：[VB2005] Validating イベント内で MsgBox を使えないジレンマ&lt;/a&gt;（Insider.NET 会議室）より：&lt;/p&gt;
&lt;p&gt;&amp;gt;項目ごとにダイアログが出るとうっとうしいと苦情を言うユーザー&lt;/p&gt;
&lt;p&gt;　項目毎にダイアログを出せ、というですよ&lt;br&gt;
　たとえば、0～100 の範囲で入力しないといけない場合に、範囲外は「0～100の範囲で入力してくださいよ！」的なダイアログ（e.Cancel = True）を出せ、というですよ。&lt;/p&gt;
&lt;p&gt;　更に80以上だったら「え？本当に80以上なの、すごいね！」みたいなダイアログ（e.Cancel = False）で御節介を焼いて欲しいそうな。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p class="p"&gt;なるほどねぇ。。。&lt;/p&gt;
&lt;p class="p"&gt;入力中に、ダイアログでメッセージを表示するのは、基本的に賛成できません。入力の流れを妨げるからです。よくある質問で、「Enter キーでフォーカスを移動させるには？」というのは、これに似た理由ですね。[Tab] キーはテンキーにはありませんので、手の移動が大きい＝入力の流れが妨げられる、と。この場合、Windows 標準のキー操作と衝突を起こすわけですが、どちらかというと、流れを妨げる方が大きな問題となるでしょう。フォーカス移動を「テンキーの [Enter] キーのみ」に絞れるなら、その方がいいとも思いますけど。&lt;/p&gt;
&lt;p class="p"&gt;あるいは、わかってやっている場合もあります。例えば、伝票入力です。伝票はすでにどこかで作られていて、それをコンピュータに入力するのかもしれません。このとき、エラーはともかく、警告で入力の流れを妨げられると、ユーザはイライラするでしょう。特に、公共事業などではデータの入力を業者が行う場合があります。業者さんは指示されたとおりに入力するのが仕事なので、指示元のデータの正誤については責任がありません。このとき、指示元のデータと違うことを指摘するならともかく、入力値が正常な範囲でありながら入力の流れを阻害するような動作は、集中力を欠かせることになります。&lt;/p&gt;
&lt;p class="p"&gt;特に、発注者と使用者が同じでない場合は、注意する必要があります。システム課などが業務の流れを知らず、「こうしてあればいいだろう」「こう使って欲しい」と思って発注しても、実際に使う場面にそぐわなければ、使われないシステムの仲間入りをする可能性が高くなります。&lt;/p&gt;
&lt;br&gt;
&lt;p class="p"&gt;と、だめだめ言っていてもなんなので、提案です。&lt;/p&gt;
&lt;p class="p"&gt;ToolTip を使ってみました。エラーメッセージは、ErrorProvider を使いました。&lt;/p&gt;
&lt;ol&gt;
 &lt;li&gt;&lt;p&gt;Visual Studio 2005 にて、Windows アプリケーションを作成します。&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;&lt;p&gt;Form に、TextBox を2つ置きます。（ひとつは、フォーカスを遷移させるためだけのもの）&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;&lt;p&gt;ToolTip と ErrorProvider も置きます。&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;&lt;p&gt;ToolTip の、ToolTipTitle プロパティに、「警告」と入力します。また、IsBaloon プロパティを True にしておきましょう。ただの ToolTip だと、どこのコントロールに対して表示されたのかわかりにくいので。&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;&lt;p&gt;TextBox1 にフォーカスし、プロパティ ウインドウで稲妻ボタンをクリックします。Validating イベントをダブル クリックします。&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;&lt;p&gt;できたイベント ハンドラに、後述のコードを書きます。&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;&lt;p&gt;さて、実行してみましょう。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="code"&gt;&lt;code&gt;Validating コードの例:
private void textBox1_Validating(object sender, CancelEventArgs e) {
    Int32   chk;
    errorProvider1.Clear();
    toolTip1.Hide(textBox1);
    if (Int32.TryParse(textBox1.Text, out chk) == false || (chk &amp;gt; 100 || chk &amp;lt; 0)) {
        e.Cancel = true;
        errorProvider1.SetError(textBox1, "0以上100以下の数値を入力してください。");
    } else {
        if (chk &amp;gt;= 80) {
            //　see: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98281
            toolTip1.Show("", textBox1);
            toolTip1.Show("80以上です。本当にいいですか？", textBox1);
        }
        e.Cancel = false;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p class="p"&gt;ErrorProvider は、規定では設定したコントロールの右側に、Icon プロパティで指定したアイコンを表示します。ここで指定したアイコンが表示できるだけの幅を、コントロールの右側に確保しておく必要があります。う～ん、ErrorProvider に、「ベルを鳴らす」機能があれば良かったのに．．．&lt;/p&gt;
&lt;p class="p"&gt;toolTip1.Show メソッドを2つ並べて書いているのは、修正されていないバグのためです。こうしていても、たまに表示されるツールチップの位置がずれます。&lt;/p&gt;
&lt;p class="p"&gt;表示されたツールチップを消すためには、フォーカスを他のフォームに移してやる必要があります。ツールチップをクリックしてもいいです。&lt;/p&gt;
&lt;p class="p"&gt;ツールチップが表示された状態で、フォームを動かすと、ツールチップが付いてきません。その後、ツールチップにフォーカスを移してツールチップを消し、もう一度ツールチップが表示されるような操作をすると、表示される場所がずれますorz あはは。。。バグ見つけちゃったよ。&lt;/p&gt;
&lt;p class="p"&gt;Validating イベントではこんな感じにしておいて、登録のアクションで、エラーなら登録させない。警告なら登録する、しないを選べるようにしておく。そんな感じかな。でも、ToolTip のバグのおかげで、使いにくいやorz&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/jitta/aggbug/113113.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>はなおか じった</dc:creator><title>VB マイグレーション ByRef と ByVal - その２</title><link>http://blogs.wankuma.com/jitta/archive/2007/05/31/78993.aspx</link><pubDate>Thu, 31 May 2007 22:28:00 GMT</pubDate><guid>http://blogs.wankuma.com/jitta/archive/2007/05/31/78993.aspx</guid><wfw:comment>http://blogs.wankuma.com/jitta/comments/78993.aspx</wfw:comment><comments>http://blogs.wankuma.com/jitta/archive/2007/05/31/78993.aspx#Feedback</comments><slash:comments>1290</slash:comments><wfw:commentRss>http://blogs.wankuma.com/jitta/comments/commentRss/78993.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/jitta/services/trackbacks/78993.aspx</trackback:ping><description>&lt;p class="p"&gt;参照型については刈歩 菜良さんに振ったので、参照渡しと値渡しを行きましょう。&lt;/p&gt;&lt;br&gt; &lt;p class="p"&gt;ByRef, ByVal で渡したプロシージャ内で、変数そのものを書き換えた場合、ByRef と ByVal がどのような結果を返すか、です。実行結果はどのようになるでしょうか。&lt;/p&gt; &lt;p class="p"&gt;その前にですね、この前のコードを、C++ で書いてみます。C++/CLI でも Managed C++ でもない、C++ です。Visual Studio 2003 のプロジェクトの追加で、「C++ コンソール アプリケーション」を選択しました。&lt;/p&gt;&lt;pre class="code"&gt;&lt;code&gt;#include "stdafx.h"
#include &amp;lt;iostream&amp;gt;

class HogeClass {
public:
    int Value;
    HogeClass() {
        Value = 0;
    };
};
void ByValFunc(HogeClass hage);
void ByRefFunc(HogeClass* hage);

int _tmain(int argc, _TCHAR* argv[])
{
    HogeClass hoge1;

    hoge1.Value = 1;
    std::cout &amp;lt;&amp;lt; hoge1.Value;  // [A]

    ByValFunc1(hoge1);
    std::cout &amp;lt;&amp;lt; hoge1.Value;  // [B]

    ByRefFunc1(&amp;amp;hoge1);
    std::cout &amp;lt;&amp;lt; hoge1.Value;  // [C]
}

void ByValFunc1(HogeClass hage)
{
    hage.Value = 2;
    //hage = new HogeClass();    // [イ]
    //hage.Value = 3;
}

void ByRefFunc1(HogeClass* hage)
{
    hage-&amp;gt;Value = 4;
    hage = new HogeClass();
    hage-&amp;gt;Value = 5;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p class="p"&gt;なんと、[イ]のところで、コンパイル エラーが出ます。ということで、“全く同じ”ではないのですが、実行してみます。&lt;/p&gt;
&lt;p class="p"&gt;結果は、114 です。&lt;/p&gt;
&lt;p class="p"&gt;やっとスタート地点だよ。。。&lt;/p&gt;
&lt;p class="p"&gt;「値渡し」は、引数「の値」を渡します。この場合、新しい HogeClass の為にメモリが確保され、全く同じ&lt;b&gt;内容&lt;/b&gt;になるようにコピーされたものが、ByValFunc の hage になります。&lt;br&gt;hage は hoge のコピーなので、ByValFunc 関数内で変更した内容は、ByValFunc で宣言された hage にのみ適用され、_tmain に伝わることはありません。このため、ByValFunc 関数の中での変更は反映されず、[B] では "1" が出力されます。&lt;/p&gt;
&lt;p class="p"&gt;「参照渡し」は、引数「への参照」を渡します。この場合、新しい HogeClass の為のメモリは確保されず、全く同じ&lt;b&gt;場所&lt;/b&gt;を参照するものが、ByRefFunc の hage になります。&lt;br&gt;hage は hoge と同じ場所を指すので、ByRefFunc 関数内で変更した内容は、_tmain で宣言された hoge と同じ場所を変更するため、hoge の内容も変わります。つまり、ByRefFunc 関数の中での変更は、hoge を直接操作したのと同じとなり、[C] では "4" が出力されます。&lt;/p&gt;
&lt;p class="p"&gt;では、なぜ[イ]の部分がコンパイル エラーになるのでしょうか。&lt;/p&gt;
&lt;p class="p"&gt;C++ では、変数の宣言時に、値を保持するもの、アドレスを保持するものとして宣言できます。&lt;code&gt;HogeClass hage;&lt;/code&gt; という宣言では、HogeClass という入れ物の、値を保持する変数と宣言します。しかし、&lt;code&gt;new HogeClass();&lt;/code&gt; は、HogeClass という入れ物を保持するために用意した場所を指す値を返します。&lt;br&gt;入れ物と、入れ物のある場所。&lt;br&gt;言い換えれば、「コーヒーカップ」と、「コーヒーカップは戸棚にあるよ」。この２つに互換性はありません。互換性がないことをコンパイル時に検出し、エラーとします。&lt;/p&gt;
&lt;p class="p"&gt;ざっくりと。変数宣言に "*" が付いていたら、「場所」を指す。付いていなければ「そのもの」を指す。こんな感じで。C 言語で必ず躓くポイントなので、さらっと次に進む。&lt;/p&gt;&lt;br&gt;
&lt;p class="p"&gt;さて、今回のエントリの C++ によるコードと、前回のエントリの VB7.0 によるコードを比べてみましょう。&lt;br&gt;まず、結果を比べます。おっと、VB7.0 での結果をまだ書いてなかったですね。VB7.0 では "125" となります。VB7.0 のコードをもう一度書きますね。&lt;/p&gt;&lt;pre class="code"&gt;&lt;code&gt;Public Class HogeClass
    Public Value As Integer
End Class

Private Sub ByValAndByRef(ByVal sender As Object, ByVal e As EventArgs)
    RemoveHandler Application.Idle, AddressOf ByValAndByRef
    Dim hoge As &lt;b&gt;New&lt;/b&gt; HogeClass

    hoge.Value = 1
    TextBox1.Text = hoge.Value.ToString()    ' [A] 1 を表示

    ByValFunc(hoge)
    TextBox1.Text += hoge.Value.ToString()   ' [B] 2 を表示

    ByRefFunc(hoge)
    TextBox1.Text += hoge.Value.ToString()   ' [C] 5 を表示
End Sub

Sub ByValFunc(&lt;b&gt;ByVal&lt;/b&gt; hage As HogeClass)
    hage.Value = 2         ' [B] で表示される
    hage = New HogeClass   ' [あ]
    hage.Value = 3
End Sub

Sub ByRefFunc(&lt;b&gt;ByRef&lt;/b&gt; hage As HogeClass)
    hage.Value = 4
    hage = New HogeClass   ' [い]
    hage.Value = 5         ' [C] で表示される
End Sub
&lt;/code&gt;&lt;/pre&gt;
&lt;p class="p"&gt;ここで注目なのは、変数 hoge を宣言しているところにある、&lt;b&gt;&lt;code&gt;New&lt;/code&gt;&lt;/b&gt; というキーワードです。C++ のコードには、 _tmain 関数での宣言にこのキーワードがありませんでした。&lt;/p&gt;
&lt;p class="p"&gt;ということで、C++ のコードにこのキーワードを入れようとすると、あっちこっちでコンパイル エラーが出るようになりますorz&lt;/p&gt;
&lt;p class="p"&gt;そして、コンパイル エラーをとって、VB7.0 のコードと等しい動きをするようになったのが、次のコード。&lt;/p&gt;&lt;pre class="code"&gt;&lt;code&gt;#include "stdafx.h"
#include &amp;lt;iostream&amp;gt;

class HogeClass {
public:
    int Value;
    HogeClass() {
        Value = 0;
    };
};

void ByValFunc2(&lt;b&gt;HogeClass*&lt;/b&gt; hage);
void ByRefFunc2(&lt;b&gt;HogeClass**&lt;/b&gt; hage);

int _tmain(int argc, _TCHAR* argv[])
{
    &lt;b&gt;HogeClass*&lt;/b&gt; hoge2;
    &lt;b&gt;hoge2 = new HogeClass();&lt;/b&gt;

    &lt;b&gt;hoge2-&amp;gt;&lt;/b&gt;Value = 1;
    std::cout &amp;lt;&amp;lt; &lt;b&gt;hoge2-&amp;gt;&lt;/b&gt;Value;

    ByValFunc2(hoge2);
    std::cout &amp;lt;&amp;lt; &lt;b&gt;hoge2-&amp;gt;&lt;/b&gt;Value;

    ByRefFunc2(&lt;b&gt;&amp;amp;hoge2&lt;/b&gt;);
    std::cout &amp;lt;&amp;lt; &lt;b&gt;hoge2-&amp;gt;&lt;/b&gt;Value;
}

void ByValFunc2(&lt;b&gt;HogeClass*&lt;/b&gt; hage)
{
    &lt;b&gt;hage-&amp;gt;&lt;/b&gt;Value = 2;
    hage = new HogeClass();
    &lt;b&gt;hage-&amp;gt;&lt;/b&gt;Value = 3;
}

void ByRefFunc2(&lt;b&gt;HogeClass**&lt;/b&gt; hage)
{
    &lt;b&gt;(*hage)-&amp;gt;&lt;/b&gt;Value = 4;
    &lt;b&gt;*hage&lt;/b&gt; = new HogeClass();
    &lt;b&gt;(*hage)-&amp;gt;&lt;/b&gt;Value = 5;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p class="p"&gt;まず、hoge2 の宣言が、"*" 付き、すなわち「場所」を指すように変わりました。&lt;/p&gt;
&lt;p class="p"&gt;ここです。&lt;/p&gt;
&lt;p class="p"&gt;VB7.0 では、というより、共通型システム（&lt;abbr title="Common Type System"&gt;CTS&lt;/abbr&gt;）では、ですね。CTS では、System.Object を継承した型はすべて、参照型となります。つまり、「場所」を指すようになっています。ここ、突っ込むと刈歩さんのセッションとバッティングするので、これくらいにしておく。&lt;/p&gt;
&lt;p class="p"&gt;ByVal で引き渡す場合、引き渡すのは変数の値なのですが、その「値」とはつまり、「参照」なのです。「この変数の実体は、この場所にあるよ」という場所への参照情報を値渡しするので、引き渡された関数からでも、引数の内容を変更することができるのです。&lt;/p&gt;
&lt;p class="p"&gt;そして、C++ のコードと見比べていただきたいのですが。あっと。ここには VB7.0 でのコードを載せましたが、C# でもそう変わらないコード内容になります。気をつけるのは、&lt;code&gt;ByRef&lt;/code&gt; が、&lt;code&gt;ref&lt;/code&gt; になることくらいでしょうか。&lt;/p&gt;
&lt;p class="p"&gt;さて、強調してあるところが違うところだと、気づいていただけたかと思います。気づいて欲しいから強調しているわけですが。&lt;/p&gt;
&lt;p class="p"&gt;hoge2 の宣言に "*" がついて、場所を指すようになったのと同様、ByValFunc, ByRefFunc の引数にも "*" がついて、ByRefFunc なんか２つも付いちゃってます。引き渡すところも、"&amp;amp;" が付いていたりしています。つまり、こうやって変数の内容を、値そのものなのか、値が格納してある場所なのか、人が指定しているわけです。ややこしいですね。&lt;/p&gt;
&lt;p class="p"&gt;VB7.0 や C# では、このようなややこしいことを、言語仕様によって人が指定しなくていいようにしてあります。便利ですね。&lt;/p&gt;&lt;br&gt;
&lt;p class="p"&gt;え？なに？&lt;br&gt;「どうして、わざわざ int 型を持つクラスを定義するの？int 型を直にやればいいんじゃない？」&lt;br&gt;ですって？その辺は、&lt;a title="&amp;rarr;wankuma.com" href="http://www.wankuma.com/seminar/20070602tokyo8/Default.aspx"&gt;刈歩さんがたっぷり説明してくださる&lt;/a&gt;でしょう。そうすると…&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/jitta/aggbug/78993.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>はなおか じった</dc:creator><title>私が考える、部分定義のメリット</title><link>http://blogs.wankuma.com/jitta/archive/2007/04/07/70528.aspx</link><pubDate>Sat, 07 Apr 2007 21:03:00 GMT</pubDate><guid>http://blogs.wankuma.com/jitta/archive/2007/04/07/70528.aspx</guid><wfw:comment>http://blogs.wankuma.com/jitta/comments/70528.aspx</wfw:comment><comments>http://blogs.wankuma.com/jitta/archive/2007/04/07/70528.aspx#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://blogs.wankuma.com/jitta/comments/commentRss/70528.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/jitta/services/trackbacks/70528.aspx</trackback:ping><description>&lt;BLOCKQUOTE&gt;
&lt;P class=quoteSource&gt;&lt;A title=→wankuma.com HREF="/rti/archive/2007/04/05/70261.aspx"&gt;部分型定義（その２）&lt;/A&gt;（R.Tanaka.Ichiro's Blog）より：&lt;/P&gt;
&lt;P&gt;ところで、&lt;/P&gt;
&lt;P align=center&gt;&lt;FONT color=#008000 size=6&gt;デザイナ&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;を使ってフォームを作るとファイルが二つに分かることはご存じでしょうか？&lt;/P&gt;
&lt;P&gt;実は、これもパーシャルクラスによるものです。&lt;BR&gt;以下は、C# で Form1 というフォームクラスを追加した時に、自動的に作成されたファイルのサンプルです。&lt;/P&gt;
&lt;P&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;ファイル名：Form1.cs&lt;BR&gt;　　public &lt;FONT color=#ff0000&gt;partial&lt;/FONT&gt; class Form1 : Form&lt;BR&gt;　　{...&lt;/P&gt;
&lt;P&gt;ファイル名：Form1.Designer.cs&lt;BR&gt;　　&lt;FONT color=#ff0000&gt;partial&lt;/FONT&gt; class Form1&lt;BR&gt;　　{...&lt;/P&gt;
&lt;P&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;さて、話を元に戻します。&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P class=p&gt;私としては、フォームだけで終わって欲しくなかったので、私が考えるメリットを書きます。&lt;/P&gt;
&lt;P class=p&gt;Visual Studio.NET、および 2003 にも、DataSet デザイナがあります。こいつでデザインすると、XML Schema と、DataSet, DataTable, DataColumn, DataRow クラスを生成してくれます。便利ですね。でも、ちょっと待ってください。このクラス、かゆいところに手が届かないのです。&lt;/P&gt;
&lt;P class=p&gt;たとえば、「このテーブルに定義されている列名の一覧が文字列配列で欲しい」と思ったとします。すると、外部から DataTable を取り出し、そこから DataColumn クラスを引き出して、列挙してやらなければならない。ちょっと待ってください。オブジェクト指向は「自分のことは自分でする」が基本じゃないですか？DataTable の中に定義されている列名の一覧を、DataTable 自身が提供せずにどうします？&lt;/P&gt;
&lt;P class=p&gt;もちろん、生成されたコードを修正すれば、そういうことも可能です。しかし。そうしてしまうと、今度はデザイナで修正するごとに、コードを修正し直さなければならない。&lt;/P&gt;
&lt;P style="FONT-SIZE: 250%; COLOR: forestgreen; TEXT-ALIGN: center"&gt;ああ、面倒くさい！！&lt;/P&gt;
&lt;P class=p&gt;ここに有効に働くのが、パーシャル クラスです。&lt;/P&gt;
&lt;P class=p&gt;フォームの修正をしても、そんなのは所詮、Initialize メソッドと宣言あたりですんでしまいます。つまり、7.x バージョンでは region で囲まれていた範囲ですね。しかし、DataSet デザイナや CrystalReports は、ファイルを書き直してしまいます。こういうものに対しても、独自の宣言を追加できてしまうのです！！&lt;/P&gt;
&lt;P class=p&gt;もちろん、ここで止まりません。独自のコード ビルダーを作ったとしても、そのコード ビルダーの使用者は、あなたが生成部分をどのように実装していようが、あなたにお構いなしに独自の宣言を追加できるのです。&lt;/P&gt;
&lt;P class=p&gt;ね？便利でしょ？&lt;/P&gt;
&lt;P class=p&gt;επιστημηさんが危惧されているように、やり過ぎると「いったいこのクラスは、いつ完成するの？！」ということになります。私は、「自動生成コード」と、「そこに手動追加するコード」くらいの切り分けにしておく方がいいんじゃないかと思います。&lt;/P&gt;&lt;img src ="http://blogs.wankuma.com/jitta/aggbug/70528.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>はなおか じった</dc:creator><title>月日は百代の過客にして行き交う技術もまた旅人なり</title><link>http://blogs.wankuma.com/jitta/archive/2007/03/12/66323.aspx</link><pubDate>Mon, 12 Mar 2007 22:38:00 GMT</pubDate><guid>http://blogs.wankuma.com/jitta/archive/2007/03/12/66323.aspx</guid><wfw:comment>http://blogs.wankuma.com/jitta/comments/66323.aspx</wfw:comment><comments>http://blogs.wankuma.com/jitta/archive/2007/03/12/66323.aspx#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://blogs.wankuma.com/jitta/comments/commentRss/66323.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/jitta/services/trackbacks/66323.aspx</trackback:ping><description>&lt;p class="p"&gt;先日の「&lt;A href="http://blogs.wankuma.com/jitta/archive/2007/03/09/65893.aspx"&gt;再帰呼び出しの代わり&lt;/a&gt;」ですが。。。&lt;/p&gt;
&lt;p class="p"&gt;すみません。思いっきり間違いを含みまくっています。一つに、古い情報を更新せずに、そのままの感覚で書いていました（タイトルは、ここにかけてみた）。一つに、書きながら、ほかのことを考えていました。シャノンさんのつっこみをベースに、修正。&lt;/p&gt;
&lt;p class="p"&gt;プログラム ポインタ → PC レジスタというので、「プログラム カウンタ」の方が正しく、Pentium では「EIPレジスタ」。&lt;/p&gt;
&lt;p class="p"&gt;プログラム ポインタのスタック領域→これは、書き方が悪かった、かな？これだと EIP レジスタ専用のスタック領域があるように理解できますね。そういうつもりではありません。「スタック セグメント」ですか。あ、IL ベースではなく、ネイティブ ベースです。って、例外を生成するのは IL ベースじゃないかorz&lt;/p&gt;
&lt;p class="p"&gt;CL → &lt;acronym title="Intermediate Language"&gt;IL&lt;/acronym&gt; が正しい。CL だと、コンパイルされてないじゃないか。&lt;br&gt;
あれ？「共通言語」って、「&lt;a href="http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/cpguide/html/cpconWhatIsCommonLanguageSpecification.asp" title="→microsoft.com"&gt;共通言語仕様&lt;/a&gt;」という言葉でしか使わないの？&lt;br&gt;
そういえば、&lt;acronym title="Common Language Runtime"&gt;CLR&lt;/acronym&gt; と &lt;acronym title="Common Language Infrastructure"&gt;CLI&lt;/acronym&gt; の違いもよくわからなかった。CLI は「共通言語基盤」。CLR が「共通言語ランタイム」。マイクロソフトによる CLI の実装が CLR、という理解でよかったはず。&lt;br&gt;
いや、だから、頭文字略語はやめてほしい。。。あ、ここで使っているのは、acronym 要素を使っています。ポイントしてみてください。&lt;/p&gt;
&lt;p class="p"&gt;ngen.exe → &lt;acronym title="Just In Time"&gt;JIT&lt;/acronym&gt; コンパイラ。何を考えていたんだろう？たぶん、「どうやってアセンブリを見ようかなぁ？」とか考えていたんだと思う。で、何で「アセンブリを見よう」なんて考えていたかというと、チラホラ話題にあがっている「"=" は等号か、代入演算か」のスレに書いているコメントを考えていたから。&lt;/p&gt;
&lt;br&gt;
&lt;div&gt;関連リンク&lt;/div&gt;
&lt;ul&gt;
 &lt;li&gt;&lt;a href="http://www.intel.com/jp/support/processors/jpident/documents.htm" title="→intel"&gt;intel プロセッサー関連ドキュメントについて&lt;/a&gt;
 &lt;p&gt;Google で検索すると、個別のマニュアルへのリンクがおいてあるページが見つかったが、インテルのトップページからそのドキュメントにたどり着けなかった。&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="http://msdn2.microsoft.com/ja-jp/library/k5532s8a(VS.80).aspx" title="→microsoft.com"&gt;msdn2 マネージ実行プロセス&lt;/a&gt;
 &lt;p&gt;う．．．こんなドキュメント、あったんだ。。。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p class="p"&gt;とりあえず、ここまで。&lt;/p&gt;&lt;img src ="http://blogs.wankuma.com/jitta/aggbug/66323.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>はなおか じった</dc:creator><title>再帰呼び出しの代わり</title><link>http://blogs.wankuma.com/jitta/archive/2007/03/09/65893.aspx</link><pubDate>Fri, 09 Mar 2007 21:28:00 GMT</pubDate><guid>http://blogs.wankuma.com/jitta/archive/2007/03/09/65893.aspx</guid><wfw:comment>http://blogs.wankuma.com/jitta/comments/65893.aspx</wfw:comment><comments>http://blogs.wankuma.com/jitta/archive/2007/03/09/65893.aspx#Feedback</comments><slash:comments>88</slash:comments><wfw:commentRss>http://blogs.wankuma.com/jitta/comments/commentRss/65893.aspx</wfw:commentRss><trackback:ping>http://blogs.wankuma.com/jitta/services/trackbacks/65893.aspx</trackback:ping><description>&lt;P class=p&gt;関数（メソッド）が、自分自身を呼び出すことを「再帰呼び出し」といいます。ディレクトリの一覧を取得するときなどに重宝します。&lt;/P&gt;&lt;PRE class=code&gt;&lt;CODE&gt;// 指定したディレクトリを再帰的に表示
[STAThread]
static void Main(string[] args) {
 if (args.Length == 0) {
  Console.WriteLine("ディレクトリを指定してください。");
 } else {
  OutputDirectory(args[0], 0);
 }
}
static void OutputDirectory(string directoryName, int depth) {
 if (Directory.Exists(directoryName) == false) {
  return;
 }
 DirectoryInfo dir = new DirectoryInfo(directoryName);
 PrintLeader(depth);
 Console.WriteLine("-{0}",dir.Name);
 DirectoryInfo[] dirInfo = dir.GetDirectories();
 foreach (DirectoryInfo item in dirInfo) {
  OutputDirectory(item.FullName, depth + 1);
 }
 FileInfo[] fileInfo = dir.GetFiles();
 foreach (FileInfo item in fileInfo) {
  PrintLeader(depth + 1);
  Console.WriteLine(item.Name);
 }
}
static void PrintLeader(int depth) {
 for (int level = 0; level &amp;lt; depth; level++) {
  Console.Write("｜");
 }
}
&lt;/CODE&gt;&lt;/PRE&gt;&lt;PRE&gt;// 実行結果
D:\DataFolder\Projects\TestSolution\tree\bin\Debug&amp;gt;tree ..\..
-tree
｜-bin
｜｜-Debug
｜｜｜tree.exe
｜｜｜tree.pdb
｜-obj
｜｜-Debug
｜｜｜-temp
｜｜｜-TempPE
｜｜｜tree.exe
｜｜｜tree.pdb
｜｜｜tree.projdata
｜App.ico
｜AssemblyInfo.cs
｜Tree.cs
｜tree.csproj
｜tree.csproj.user
&lt;/PRE&gt;
&lt;P class=p&gt;このプログラムの考え方の一例を示します。&lt;/P&gt;
&lt;P class=p&gt;指定されたディレクトリに存在する、ディレクトリの一覧を取得します。取得したディレクトリ一覧について、それぞれのディレクトリでまた存在するディレクトリの一覧を取得します。ディレクトリ内にディレクトリが存在しなければ、ファイルの一覧を取得し、表示します。そして、上のレベルへ制御を戻します。&lt;/P&gt;
&lt;P class=p&gt;ところが、この方法は少し注意が必要です。&lt;/P&gt;
&lt;P class=p&gt;ここの例では C# でコードを作っていますが、コンピュータは C# を理解できません。そこで、コンピュータにわかる言語にコンパイルします。C# の場合、コンパイルした結果は &lt;ACRONYM title="Common Language"&gt;CL&lt;/ACRONYM&gt; という言語になりますが、この言語を直接実行することは出来ません。実行時に、ngen.exe というツールでもう一度、今度はネイティブ（コンピュータが直接理解できる言語）にコンパイルされます。&lt;/P&gt;
&lt;P class=p&gt;ネイティブ言語、すなわち &lt;ACRONYM title="Central Processing Unit"&gt;CPU&lt;/ACRONYM&gt; が理解できる言語を実行するとき、&amp;#8220;プログラム ポインタ&amp;#8221;（または、プログラム カウンタ）というレジスタがあり、このポインタで、次に実行するべき命令の位置を示します。関数呼び出しを行うと、このプログラム ポインタの現在の値（および、他のレジスタの現在値）をスタックへ積み、呼び出される関数のアドレスで上書きします。そして、関数の実行が終わったら、プログラム ポインタの値をスタックから取り出し、元の処理を続けます。&lt;/P&gt;
&lt;P class=p&gt;関数の呼び出しが多くなって、スタックする領域がなくなると、「スタック オーバーフロー」という実行時エラーが発生することになります。&lt;/P&gt;
&lt;P class=p&gt;反対に考えると、「スタック オーバーフロー」が発生したら、どこかで関数呼び出しがループしていると考えられます（あるいは、単に深すぎる）。このエラーは次のようなプロパティ設定をすると、簡単に発生させることが出来ます。&lt;/P&gt;&lt;PRE class=code&gt;&lt;CODE&gt;// スタック オーバーフローが発生する例
private int someValue;
public int SomeValue {
    get { return SomeValue; } // 大文字と小文字を間違えた！！
}
// SomeValue プロパティへのアクセスは、SomeValue プロパティを呼び出すため、無限再帰する。
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P class=p&gt;このように再帰呼び出しは、ある処理をするためには必要なのですが、プログラム ポインタのスタック領域という、比較的小さなエリアの大きさによって制限されます。また、CPU の実行レベルで考えても、レジスタ群のスタックやプログラム ポインタの書き換えは、コストがかかる方法です。&lt;/P&gt;
&lt;P class=p&gt;そこで、再帰呼び出しと同じ結果を、別の方法で実現します。&lt;/P&gt;
&lt;P class=p&gt;こういう時に用いるのが、System.Collections.Stack クラス／System.Collection.Queue クラスです。スタックは、後入れ先出し（&lt;ACRONYM title="Last In First Out"&gt;LIFO&lt;/ACRONYM&gt;）の記憶領域を提供してくれます。キューは、先入れ先出し（&lt;ACRONYM title="First In First Out"&gt;FIFO&lt;/ACRONYM&gt;）の記憶領域を提供してくれます。&lt;/P&gt;
&lt;P class=p&gt;どうするかというと、もう一度コードを見ます。ここで、再帰呼び出しをしているのは、foreach ブロックの中です。このループで、再帰呼び出しをしているところで、ループ内で使っている変数のスナップ ショットをとり、そのスナップ ショットをスタックに待避、新しい値で変数を上書きして処理をやり直せば、再帰処理をしているのと同じ動きをすることになります。&lt;/P&gt;
&lt;P class=p&gt;・・・面倒です。&lt;/P&gt;
&lt;P class=p&gt;なので、使いません。（おい）&lt;/P&gt;
&lt;P class=p&gt;ケース バイ ケース。ものは使いようなのです。&lt;/P&gt;
&lt;P class=p&gt;このコードでは、ディレクトリ構造を表示しました。表示するためには、今表示している内容がなんなのか、覚えておかなければなりません。覚えておかなければならないものがあるため、自分で覚えておかなければならないものを待避させなければならない場合は、再帰の方が楽です。&lt;/P&gt;
&lt;P class=p&gt;しかし、「ディレクトリ中のすべてのファイルを、{アタッチしたい | 更新日付が知りたい | フルパス名が知りたい}」という場合、ファイルにアクセスする順番は関係ありません。順番が関係ないなら、覚えておくものはありません。こういう場合、再帰呼び出しよりも低コストなので、使います。&lt;/P&gt;&lt;PRE class=code&gt;&lt;CODE&gt;// Main を少し変更
static void Main(string[] args) {
    if (args.Length == 0) {
        Console.WriteLine("ディレクトリを指定してください。");
    }
    else {
        DateTime start = DateTime.Now;
        OutputDirectory(args[0], 0);
        DateTime t1 = DateTime.Now;
        Console.WriteLine("----------");
        OutputDirectory(args[0]);
        DateTime t2 = DateTime.Now;
        Console.WriteLine("{0} / {1}", t1.Subtract(start), t2.Subtract(t1));
    }
}
// 指定したディレクトリ以下のフルパス名を表示
static void OutputDirectory(string directoryName) {
    // Queue に、次に列挙したいディレクトリを放り込むことにする
    System.Collections.Queue q = new System.Collections.Queue();
    DirectoryInfo dir = new DirectoryInfo(directoryName);
    // 初回が回るように、トップを放り込む
    q.Enqueue(dir);
    while (q.Count &amp;gt; 0) {
        // キューから取り出して、書く
        DirectoryInfo info = q.Dequeue() as DirectoryInfo;
        Console.WriteLine(info.FullName);
        // ディレクトリ内のディレクトリを、キューに放り込む
        DirectoryInfo[] dirs = info.GetDirectories();
        foreach (DirectoryInfo item in dirs) {
            q.Enqueue(item);
        }
        FileInfo[] files = info.GetFiles();
        foreach (FileInfo item in files) {
            Console.WriteLine(item.FullName);
        }
    }
}
&lt;/CODE&gt;&lt;/PRE&gt;&lt;PRE&gt;// 実行結果
-tree
｜-bin
｜｜-Debug
｜｜｜tree.exe
｜｜｜tree.pdb
｜-obj
｜｜-Debug
｜｜｜-temp
｜｜｜-TempPE
｜｜｜tree.exe
｜｜｜tree.pdb
｜｜｜tree.projdata
｜App.ico
｜AssemblyInfo.cs
｜tree.cs
｜tree.csproj
｜tree.csproj.user
----------
D:\Visual Studio Projects\TestSolution\tree
D:\Visual Studio Projects\TestSolution\tree\App.ico
D:\Visual Studio Projects\TestSolution\tree\AssemblyInfo.cs
D:\Visual Studio Projects\TestSolution\tree\tree.cs
D:\Visual Studio Projects\TestSolution\tree\tree.csproj
D:\Visual Studio Projects\TestSolution\tree\tree.csproj.user
D:\Visual Studio Projects\TestSolution\tree\bin
D:\Visual Studio Projects\TestSolution\tree\obj
D:\Visual Studio Projects\TestSolution\tree\bin\Debug
D:\Visual Studio Projects\TestSolution\tree\bin\Debug\tree.exe
D:\Visual Studio Projects\TestSolution\tree\bin\Debug\tree.pdb
D:\Visual Studio Projects\TestSolution\tree\obj\Debug
D:\Visual Studio Projects\TestSolution\tree\obj\Debug\tree.exe
D:\Visual Studio Projects\TestSolution\tree\obj\Debug\tree.pdb
D:\Visual Studio Projects\TestSolution\tree\obj\Debug\tree.projdata
D:\Visual Studio Projects\TestSolution\tree\obj\Debug\temp
D:\Visual Studio Projects\TestSolution\tree\obj\Debug\TempPE
00:00:00.0312500 / 00:00:00.0781250&lt;/PRE&gt;
&lt;P class=p&gt;表示されている順番を見ると、再帰の例のように、ツリー表示には向かないことがわかると思います。何度かトライして、できなかったというわけでは、断じてあります。&lt;/P&gt;
&lt;P class=p&gt;しかし。。。実際に実行してみると、再帰処理の方が速かったorz...&lt;/P&gt;
&lt;P class=p&gt;K&amp;amp;R 本あたりに、関数を呼び出すことによる、プログラム ポインタの書き換えと、ローカル変数の待避、および再生成のオーバー ヘッドの方が大きい、と書いてあったと思うんだけど。すると・・・キューやスタックを使うメリットがない？？？&lt;/P&gt;&lt;img src ="http://blogs.wankuma.com/jitta/aggbug/65893.aspx" width = "1" height = "1" /&gt;</description></item></channel></rss>