2007年05月31日

DataSetのカラムで列挙型を扱うには

   このエントリーをはてなブックマークに追加 Clip to Evernote
型付DataSetのテーブルのカラムの型を、int ではなく、独自の列挙型にするには、2つの方法がある。

ひとつは、型付DataSetの定義を行う場合に列のデータ型を列挙型に指定する方法。
これは、デザイナー画面で、DataTypeプロパティの値を System.Int32 などから、独自の型 Gushwell.Genderなどを指定してあげればよい。
ドロップダウンリストには現れないので、手入力になる。

もうひとつは、partial クラスを使う方法。

型付DataRowクラスの partialクラスを作成し、その中に、列挙子用のプロパティを定義し、データ変換コードを書けばよい。

例えば、Gender というカラムがあった場合、

public partial class MyRow : System.Data.DataRow {
public Gender EnumGender {
get {
try {
return (Gender)(this.Gender);
} catch {
return Gender.Unknown;
}
}
set {
this.Gender = (int)value;
}
}
}

のように書けば良い。C#からは、Genderカラムではなく、EnumGenderカラムを参照するようにする。こうすることで、間接的ではあるが、DBのカラムを列挙型として扱うことができる。

後者のやり方は、try-catchで例外処理を記述できるのがメリット。
  

Posted by gushwell at 21:38Comments(0)TrackBack(0)

2007年05月30日

csc.exe その後

   このエントリーをはてなブックマークに追加 Clip to Evernote
先日の記事「csc.exe って常駐ソフトでしたっけ?」で、csc.exeが終わらないときがある、ということを書きましたが、その後、この現象は出ていません。

それと、関係があるのかどうか分からないのですが、「Microsoft Visual Studio は操作の完了を待機しています」で書いた、

Microsoft Document Explorer の、オプション画面を開くのに、10分近くかかるようになってしまった。

という現象も、今日確認したら、出なくなっていました。
この2つは、関係あるのかな。
Visual Studio 2005でF1キーを押したときって、csc.exe が起動されて、その csc.exe が終わらないために、ヘルプがなかなか起動しなかったとか...

あくまで推測ですが.



  
Posted by gushwell at 20:56Comments(0)TrackBack(0)

2007年05月29日

独自クラスでforeach を書けるようにするには

   このエントリーをはてなブックマークに追加 Clip to Evernote
自分の知識を整理する意味で、まとめてみました。

foreachが使える最も簡単な独自のクラスを作成するには、以下のように書けばよい。

public class MyCollection  {
public IEnumerator GetEnumerator() {
yield return 1;
yield return 2;
yield return 3;
yield return 4;
}
}

こうすれば、

MyCollection col = new MyCollection();
foreach ( int n in col ) {
Console.WriteLine(n);
}

のように、foreachが書ける。GetEnumerator() というメソッドがあれば、IEnumerable を継承する必要はない。

しかし、MoveNext,Currentを使うことはできない。

MyCollection col = new MyCollection();
IEnumerator ite = col.GetEnumerator();
while ( ite.MoveNext() ) {
int n = ite.Current;
Console.WriteLine(n);
}

と書いても、MoveNextが無いとエラーになってしまう。
これに対応するには、IEnumerableインターフェースから継承する必要がある。

public class MyCollection : IEnumerable {
public IEnumerator GetEnumerator() {
yield return 1;
yield return 2;
yield return 3;
yield return 4;
}
}

しかし、

    int n = ite.Current; 

でキャストできないとエラーになるので、

    int n = (int)ite.Current; 

としてあげなければならない。このキャストを不要にするには、ジェネリックなIEnumerableを継承すればよい。

public class MyCollection : IEnumerable<int> {
public IEnumerator<int> GetEnumerator() {
yield return 1;
yield return 2;
yield return 3;
yield return 4;
}

IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}

こうすれば、

MyCollection col = new MyCollection();
IEnumerator<int> ite = col.GetEnumerator();
while ( ite.MoveNext() ) {
int n = ite.Current;
Console.WriteLine(n);
}

と書ける。
IEnumerableから継承したものと比べると、書く手間はかえって増えているが、より安全なコードにはなっている。

ただ、foreachしか使わないのならば、最初のコードで十分だろう。

ところで、単に独自の型指定のコレクションを作るだけならば、System.Collections.ObjectModel.Collectionを継承するだけでもよい。

class MyList : System.Collections.ObjectModel.Collection<int> {
}

これだけで、GetEnumerator はもちろん、Add, Insert, Remove, IndexOf, Clear などのメソッドが利用可能だ。  
Posted by gushwell at 21:15Comments(2)TrackBack(1)

2007年05月26日

GetEnumerator() vs. GetEnumerable() その2

   このエントリーをはてなブックマークに追加 Clip to Evernote
コメントの文字数制限を越えてしまったので、新規記事としてアップします。

お二人のコメントで、foreach についてあやふやだったことが、だいぶ整理できてきました。Thanks! です。

foreachは、IEnumerableインターフェースを実装していることが前提だったと思ったのですが、IEnumerableを実装していなくても、GetEnumerator()メソッドを実装していれば、foreachを受け付けてくれるように変更されていたんですね。(それとも最初から?)

そのため、static メソッドでは、IEnumerableを返す必要がある。
いっぽう、インスタンスメソッドでは、IEnumerableを実装する、しないにかかわらず、GetEnumerator()を実装していさえすれば、

MyClass obj = new MyClass();
  foreach (object o in obj) {
...
}

と書ける。
ただ、逆順をたどるような反復子も用意したい場合には、GetEnumrator()という名前は使えないので、IEnumrator を返すメソッドを書いても、エラーになる。
IEnumerableを返すメソッドにしなければならない。

ってことですね。

http://msdn2.microsoft.com/ja-jp/library/9yb8xew9(VS.80).aspx

には、
----
インターフェイスを省略すると、Current の戻り値の型を object よりも明確に定義できるので、結果としてタイプ セーフになります。
----
と書いてあります。ふーん、そうなんだ。
  
Posted by gushwell at 11:22Comments(2)TrackBack(1)

2007年05月24日

GetEnumerator() vs. GetEnumerable()

   このエントリーをはてなブックマークに追加 Clip to Evernote
C#で、

 public class MyClass {
public IEnumerable<int> GetEnumerator() {
yield return 1;
yield return 2;
yield return 3;
yield return 4;
}
}

というコードを書けば、

 MyClass mc = new MyClass();
foreach ( int i in mc.GetEnumerator() ) {
Console.WriteLine(i);
}

と foreach 文が書ける。最も手軽な反復子の書き方だ。

でも、2つのメソッドで、値を順に取り出したいときなどforeach 文 が使えない場面もある。
こんなときは、MoveNext(), Current メソッド使うのだが、ちょっと、困った。

 IEnumerator<int> e = mc.GetEnumerator().GetEnumerator();
while ( e.MoveNext() ) {
Console.WriteLine(e.Current);
}

これで、一応目的は達したのだが、GetEnumerator().GetEnumerator();
という部分は、何かおかしい。

そもそも、IEnumerable<> を返しているのに、GetEnumerator() という名前をつけていることが変だ。

やはり、

public IEnumerable<int> GetEnumerable() {
yield return 1;
yield return 2;
yield return 3;
yield return 4;
}


と GetEnumerable() が良さそうだ。

でも、

GetEnumerable を Google で日本語のページを検索すると、たった数件しかヒットしない。
何でだろう?

よくよく考えたら、戻り値が、IEnumerableの方を直すべきだった。GetEnumerator()なんだから、IEnumerator を返すメソッドにしないとね。


※コメントの内容を反映して一部書き直してます。
  
Posted by gushwell at 22:52Comments(6)TrackBack(1)

2007年05月22日

csc.exe って常駐ソフトでしたっけ?

   このエントリーをはてなブックマークに追加 Clip to Evernote
タスクマネージャを見てたら、VS2005は終了しているのに、csc.exeが動作している。何でだろう。それとも、別の csc.exe だろうか?

で、以下のコードを書いて調べてみた。

Process[] ps = Process.GetProcessesByName("csc");
foreach ( Process p in ps )
Console.WriteLine(p.MainModule.FileName);

表示された結果は、

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc.exe

やっぱり、C#のコンパイラだ。

どうしてかな?
もう少し深く調べたいが、時間がない...  
Posted by gushwell at 22:20Comments(2)TrackBack(0)

2007年05月21日

Microsoft Visual Studio は操作の完了を待機しています

   このエントリーをはてなブックマークに追加 Clip to Evernote
Visual Studio 2005で、F1キーでヘルプを開こうとすると、やたらと遅い、最近特に遅くなったような気がする。10分くらいかかるのでイライラする。

この時にでるメッセージは、
「Microsoft Visual Studio は操作の完了を待機しています。この遅延が日常的に発生する場合は、この問題をマイクロソフトに報告してください。 」

その間、Visual Studio 2005 の操作もできない。

F1キーで止まるのは、Visual Studio 2005 を起動し、最初のF1キー押下時だけなので、まあ、なんとか我慢できる状況。

Googleで検索しても、有効な解決策は載っていない。同様の現象に悩んでいる人が何人かいるようだが、有効な解決策はみつからなかった。

会社の人にアドバイスを受けて、なんとか1分以内で起動するようになった。

採った対策は、以下の3つ。

1.Microsoft Document Explorer の、オプション画面で、
  ・「オンラインではなく、ローカルで実行」にチェック。
  ・検索するプロバイダは、「ローカルのヘルプ」 のみにチェック。
  ・codezoneコミュニティに表示されているものは、すべてチェックをはずす。

2.MSDN ライブラリを最新のものにする。

3.SQL Server 2005 のBooks Onlineも最新のものにする。

ただ、どれが有効だったのかまでは把握できていない。

#今まで、MSDN ライブラリ、SQL Server Books Onlineが最新じゃなかったのか?
#と突込みが入りそうですが...

しかし、今度は、Microsoft Document Explorer の、オプション画面を開くのに、10分近くかかるようになってしまった。
単に、起動時にかかっていたのが、オプション画面のほうに移っただけのような感じ。
  
Posted by gushwell at 22:04Comments(0)TrackBack(0)

2007年05月15日

データ構造とプログラムの構造をあわせることは重要。

   このエントリーをはてなブックマークに追加 Clip to Evernote

あるテキストファイルを読み込み、解析するプログラムを作成したのだが、そのときの失敗。

いわゆるインタープリタパターンを利用して、

NodeA -> NodeB -> NodeC -> NodeD -> NodeB

のように、ノードを次々と移動しながら、テキストを解析するコードを書いたわけですが、深く考えずに書いたので、テキストの終わりになるまで新たなNodeをどんどん作りだし、その Nodeにある Execute メソッドを呼ぶような実装になってしまいました。
いちおうこれで目的は達したのですが、巨大なテキストを読み込むと、どんどんメソッドの呼び出しがネストしていき、スタックを大量に使う羽目になってしまいました。

スタックオーバーを起こしているわけではないので、まあいいか、とも思ったのですが、どうも気になるので再度見直すことにしました。

問題は、データの意味的な構造を考えずに、文字列の羅列としてこのテキストファイルを処理しようとしたのが、問題でした。
意味的構造にあわせ、Node の途中で、returnするように変更。

すると、今まで、ちょっと強引に実装していた部分が解消され、そのために用意していたフィールドが不要になったり、最終的に構築する木構造も、より意味を反映できるものになりました。

データ構造にプログラムの構造をあわせることって、当たり前だけどものすごく重要だと思ったしだい。


そういえば、最近、失敗した話ばかりだな。
「窓際プログラマーの失敗だらけ」にブログ名を変えようかな...
  
Posted by gushwell at 21:51Comments(0)TrackBack(0)