年別アーカイブ: 2010年

47件の投稿

VB to C# 3

VBプロジェクトからC#プロジェクトへの書き換えは、
次のように三つのプロジェクトを開いて作業しています。
一つ目はオリジナルのVB2010プロジェクト(以下[VBPro]といいます)、
二つ目はSharpDevelopで変換したC#プロジェクト(以下[SDevPro]といいます)、
三つ目は新規のC#プロジェクト(以下[新規Pro]といいます)です。

最初は二つ目のプロジェクト[SDevPro]ですべて作業していたのですが、
SharpDevelopの変換は不十分で、
それに沢山の修正を加えてゴチャゴチャにするよりも、
新たにプロジェクトを構築していく方がすっきりしてよいと気づき、
新規のプロジェクトを一から構築することにしました。

まず、Formを継承していないクラスファイルは問題が少ないので、
ほぼそっくり[SDevPro]から[新規Pro]にコピーします。

VBはすべてがいい加減で(言葉は適切ではありません)、
C#はすべてが厳密だという問題が出てきます。

すぐ問題になるのが名前空間[namespace]です。
プロジェクトが大きくなるとサブフォルダを作ることは至極当然です。
VBでは、特に[namespace]を気にしなければ、
フォルダに関係なく一つの名前空間の下に管理されます。
C#ではフォルダをつくり、その中にクラスなりフォームなりを作成すると、
そのクラスの[namespace]は、
[ルート名前空間 + ドット + フォルダ名]になります(Javaと同じです)。

プロジェクトのなかでも別のフォルダを使うときには、
[using]で必要なサブフォルダ=[namespace]を呼び込んでおかなければなりません。

後でフォルダ名を変えたり、ファイルの移動をしたりするとどうなるか。
ソリューション エクスプローラでファイルを[切取]、[貼り付け]でフォルダを移動しても、
[Visual SourceSafe 2005]は問題ありませんが、
当該クラスで記述した[namespace]は自動では変更してくれませんので、
手動で変更しなければいけません。

100%ではありませんが、
この辺りはVS2010の[リファクター]やDecXpressの[RefactorPro!]が十分働いてくれます。

フォームを継承したクラス(要するにForm)のデザイン画面は、
[VBPro]の画面をコピーし貼り付けても問題ないようです。
コードは[SharpDevelop]で変換した[SDevPro]のコードをコピーします。

どちらにしても自動変換の後はたくさんのエラーが表示されます。

VBメソッドの[Optioal]はC#でサポートしていない」ので、
一部書き換えを始めていましたが、C#2010からC#でもこれをサポート。
C#ではもっと簡単に、
引数定義の後ろに[=]に続いてデフォルト値を書くだけでいいと分かり(たとえば[= true])、
「よかった!!」という感じです。
実はこの変更もどのように統一的な形にするか悩んでいました。

C#への書き換えで気づいたのは、
VBのプログラミングムでは私自身「ずいぶんいい加減に書いてきたな」ということです。

その一つが、[ByRef]の使い方です。
メソッド側で変更がある場合は、碌に考えもしないで[ByRef]を使っていました。
VBでは害にもならないのですが、
C#ではコールする側にも[ByRef]に相当する[ref]を書かなければいけません。
しかもコールする側でこの変数に値を代入しておかなければエラーになります(VBでは警告)。

反対にメソッドを呼ぶ側でなく、呼ばれるメソッド側で値を作る場合は、
呼ぶ側も呼ばれる側も[out]キーワードを付けなければいけませんし、
呼ぶ側は変数定義だけでにしておかなければいけません。
呼ぶ側で変数に値を設定するとエラーになります。

もう一つ面倒なのは、C#で参照渡し([ref]あるいは[out])でメソッドを呼ぶとき、
オブジェクトの[プロパティ]を引数に渡すことはできません。
例えば、商品台帳(クラス)の価格プロパティをメソッドで変更しようとして、
価格プロパティだけをメソッドに渡すことができません。
プログラムを改変する必要があります。
この辺りは「C#は融通が利かない」とみるか、「厳密でいい」とみるか意見の分かれるところです。

現在DBでは[Ado.Net]、[Linq to SQL]、[Linq to EF]を節操もなく使っていますので全面見直しです。
まだ先は長そうです。

どちらにしても、
[VB to C#]の変換作業はVBプログラマにとって最も効率のいいC#の勉強法だと思います。

C# 参考書

昔-Windows以前の世界では-FortranやCを使っていて、
オモチャっぽいBasicは好きではありませんでした。

WindowsでVBが発売されたとき、
統合開発環境=IDEの充実した言語としては他にVC++しかありません。
VC++のフレームワークはあまりにゴチャゴチャしていて、
予想どおり大多数の人はVC++を使って来ませんでした。

私もVC++はあまり使わず、結局長い間VBを使ってきました。
VBの教科書としてはBalenaの翻訳本がとてもいいと思います。
BalenaがVB.NETに書き換えたとき躊躇せず購入しましたし、
VB2005の解説書も購入しました。
私は完全にBalenaを信頼しています。

今回本格的にC#の勉強をしようと参考書を物色しましたが、
日本語の「いい教科書がない」と痛感しました。
書店には「・・・入門」はたくさんありますが、中級以上の本がない。

私はよく思います。
「なぜ日本語のいい教科書がないのだろう」と。
理由は色々あると思いますが、一つは投資対効果でしょう。
一冊の本をしっかり書くことは大変な労力を必要としますが、
数年でバージョンが変わるソフトを追いかけて、
大して売れもしないうちに次々教科書を出版するのは採算に合わないのでしょう。

英語圏であればそれなりの購買層があるが、
日本語に特化すると商売にならないのでしょう。
結局私たちは中級以上の本は賞味期限を過ぎた翻訳本か、
それが嫌なら原書を読むしかありません。

ついでですが、「調べる」にはオンラインヘルプはいいが、
「勉強」には本の方が数段勝ると思います。

今回C#のプログラムを書くにあたって、いい教科書に出会えません。
[プログラミング VIsual C# 2005]はもはや話題が古くLINQ等の記述がありません。
[Pro C# 2010 and the .NET 4 Platfrom](Apress)は1600ページ以上あって、
英語ですから拾読みするには適当ではありません。通読する時間などありません。
[C# 4.0 In a nutshell](O’Reilly)がリファレンスとしては一番いいかもしれません。

出版社に提案があります(出版社がこのブログを読んでいるとは思いません。独り言です)。
日本語の[・・・入門]はやめて、英語の定評のある参考書の翻訳本を素早く出版していただきたい。
これは出版社に対してのお願いというよりマイクロソフトへのお願いです。
マイクロソフトは[Microsoft Press]だけでなく、
他社の書籍に対してもいい翻訳本を迅速に出す工夫をしていただきたいと思います。

いい教科書があるかどうかは、その言語が広く使われるかどうに大きく影響します。

このような状態では、英語に弱い日本のソフト技術者は、最前線からどんどん追いやられてしまいます。

インドや中国の技術者の進出を見れば、彼らの勢いを肌で感じるでしょう。
ソフトにかかわる人は、「彼らを使えば安く開発できる」とのんきなことをいっている場合ではないでしょう。
ソフトウェア技術者も英語の技術書を「読む」くらいは身につけなければいけません。

大学の教養科目の英語で「文学書」の一節を勉強するなど間違っています(私の学生時代)。
大学生になればそれぞれに教養として専門書が読めるようにすべきです。
専門書はそもそも文学書と違って「凝った」表現はないのです。
自分の専門分野に限れば単語も数多くあるわけではありません。
ある種「慣れ」で、母国語程度とはいきませんが、慣れればいくらでも読めるのです。

今の大学の教養授業は変わったのでしょうか。

VB to C# 2

VB.NETからC#.NETへの変換では、
SharpDevelopは大いに助かるのですが、
結局ややこしいところは自動処理してくれなくて手作業で書き直さなければいけません。

全面書き換えには次のようなものがあります。

画面
LINQ
インデクサ

そのほかVBでよく使うメソッドでC#ではどうかけばいいのか分からないケースがあります。
たとえば、二つの日付の差の日数を計算する[DateDiff]や変数に数字が入っているかを調べる[isNumeric] 等をC#ではどう書けばいいか結構調べまわることになります。

LINQでは明示的に型指定のない変数(VBではDim、C#ではvarで宣言)をよく使います。
VBではつぎのように条件文の外で変数を宣言し、条件によるLINQ文の結果をその後で使っていくことができます。

Dim query
If true then
    query= From rec In 商品tbl Where rec.CD = “1234”
Else
    query= From rec In 商品tbl Where rec.CD = “5678”
End If

それどころが明示的に型指定のない変数をクラス変数(フィールド)にさえ使えます。

一方C#では、型指定のない変数は厳密にローカルにしか使えませんし。
上のコードのように初期化なしの宣言だけも許されません(nullでの初期化も不可)。

C#では型指定するか、プログラムの構造を変えるしかありません。

また、[LINQ toSQL]と[LINQ to Entiry Framework](以下LINQ to EFと書きます)との使い分けがまだよく分かりません。
おそらく、[LINQ to EF]に統一すべきだと思いますが、我がプログラムはまた統一していません。
[LINQ to SQL]は身軽な感じがしているので、
簡単なSQLはこちらが便利かなと思っています。

VBではLINQやデリゲートやジェネリックを使ってきましたが、
VBの緩い約束事にしたがって、「いい加減に使ってきたかな」という感想を持っています。

この際、「デリゲート、ジェネリック、LINQ、ラムダ式をキッチリ理解しなければいけない」
と考えています。
正味1、2ヶ月は必要かもしれません。

VB to C#

途中まですすめたVB.NETプロジェクトをC#.NETに書き換えています。おそらく10万行程度のコードだと思います。

まずSharpDevelpoでVB2008のプロジェクトをC#プロジェクトに一括変換し(確か、SharpDevelopはVB2010の変換ができない)、VS2010を使ってC#2008のプロジェクトをC#2010にアップグレード、SharpDevelopで変換できなかったVBのコードを少しずつ切り出し、インターネットサイトを利用しC#に変換しました。

機械的な変換処理でやれるところまでやって、VS2010C#でプロジェクトを開くとたくさんのエラーが表示されます。内容は一言でいえば、型指定等VBは緩くC#は厳しいことからくるエラーです。

VBではVariant型という大変便利な型がありましたし、その流れを汲んで暗黙の処理がたくさんあります。基本的にVBにはプログラミングする上で色々横着ができます。

また、モジュールというグローバル変数やメソッドを定義できる仕組みがありますし、メソッドにはオプショナルという引数にデフォルト値を設定できる仕組みがあります。また配列クラス変数に対して、プロパティを定義すればプロパティを使って配列要素にアクセスできますが、C#ではそれができません。

このようにC#は厳密といえば厳密、面倒といえば面倒な言語です。

C#プロジェクトを開くと、プロジェクト全体のエラーではなく、開いたコードに対してのエラーが表示されます。ざっと1ファイル(1000行程度か。Partial Classでは1クラスは数ファイルのことも)100程度のエラーが出てきます。エラーをつぶしていけば、後でみるファイルほどエラーの数は少なくなるでしょうが、どちらにしても相当数のエラーをつぶしさなければいけません。

私は長年VBを書いてきましたので、少し気取っていえば裏技的あるいは高度なVBの技法を取り入れていますので、その分C#への移植は難しくなります。

今は半分機械的にエラーをつぶしていますし、その場で分からないこと面倒なことはコメントアウトしていますので、とりあえずの作業の後に高度にC#を研究しなければいけないかもしれません。

フォームには大抵深刻なエラーがあってデザイン画面を表示することができません。すべての画面はつくりかえた方が早いでしょう。

VB2C#の変換は予想以上に大変な作業ですが、この際勉強だと思えば楽しみ半分です。

このプロジェクトのエラーをすべてつぶしたときには、一端のC#プログラマになっているでしょう。

SQL Server のページング、 Power Shell

Accessプロジェクトのトラブルシューティングはまだ続いています。
この2ヶ月で細かいバグを10個ほど修正し、全面書き換え2本のコードを書いています。
1本はほぼ完成。もう一本も今週中には終わらせたいと思っています。

細かい手直しの部類です。次のようなものがありました。

SQL Serverの結果データをAccessシートで表示するには、レコード数10,000が限界のうようです。

数万レコードをページングして自由に表示するには工夫が必要です。
幸いSQL Server 2008では新たに、共通テーブル式(CTE)ROW_NUMBERが使えます。

CTEの構文は次のようなものです。

WITH <CTEの名前>(<列の名前>)
AS
(
<クエリ>
)
(SELECT * FROM <CTEの名前>)

ROW_NUMBERは<クエリ>の結果に自動で行番号を振ります。
その列名を今RowNumberとして次のような文を作成します(@開始行等は変数名です)。

WITH tmpTable
AS
(
SELECT T.*, ROW_NUMBER() OVER (ORDER BY 商品CD) AS RowNumber FROM [WRK_商品] T
)
SELECT * FROM tmpTable
WHERE RowNumber BETWEEN @開始行 AND (@開始行+@行数-1)

Accessフォームにデータを連結するには、フォームのレコードソース・プロパティにSQLやテーブル名を設定します。
ところが設定する文の長さが128文字(正確ではありません。忘れました)に制限されていて、
どうしても上の文を128文字以下にできません。

次の手はこれを下のように引数付きのストアドプロシージャにすることです。

CREATE PROCEDURE [Sp_商品表示] (
@開始行 integer,
@行数 integer
)
AS
BEGIN
WITH tmpTable
AS
(
SELECT T.*, ROW_NUMBER() OVER (ORDER BY 商品CD) AS RowNumber FROM [WRK_商品] T
)
SELECT * FROM tmpTable
WHERE RowNumber BETWEEN @開始行 AND (@開始行+@行数-1)
END

ところが今度は引数付きのストアドプロシージャをどうやって先のプロパティに設定すればいいのかわかりません。
あちこち情報を探し回りましたが、使っているAccessそのものが古い(2003)し、なかなか思った解決策が見つかりません。
やっと探し当てました。
次のようにストアドプロシージャをExecでコールすればいいのです。
結構早く反応します。

Form_商品表示.RecordSource = “Exec [Sp_商品表示] ” & 開始行 & “,” & 行数

話は変わりますが、私はPerlをよく使います。
DBの結果出力が正しいかどうか。
SQL Serverでは結果セットをCSVに書き出すことができます。
正しい結果のCSVがあるとして、これとテスト結果との突合せにPerlで小さいプログラムを書けば簡単に照合できます。
テキストデータ(ファイル)の検査とか、変更とかこれほど便利なツールはないと、
Perlをとても重宝しています。

また話は変わりますが、今回色々調べていて、Windows Power Shellなるものがあることを知りました。
これまでは、バッチブログラムの実行はコマンドプロンプトWindowを開いて、いくつかのDOSコマンドを敲き、プログラムを起動していました。

このことに不便は感じていなかったのですが、Windows Power Shell(以下PS)があることを知りましたので、どんなものか勉強してみました。
Perlのようなものかと思いましたが、確かにPerlの記法も取り入れていますが、
WindowsでGUIを使って色々操作していたこと(システム管理)が、
大抵このPSで実行可能らしいことがわかりました。
Perlとは違う場所でこれはこれで「使えそうだ」という感想を持っています。