カテゴリー別アーカイブ: Visual Studio 2008

デリゲートって型推論あるの?

例えばボタンクリックにイベントハンドラを追加するには

btnHello.Click += new EventHandler(btnHello_Click);

などとやるわけだけど、いつの間にか無意識に、こんな風にやってしまっていることに気づいた。

btnHello.Click += btnHello_Click;

あれ、まずいかな?と思ったけど、なんら支障なく動いているように見える。

これってどういう仕組み?型推論?

調べても匿名デリゲートやラムダ式のことは出てくるけど暗黙の型付けについては余り出てこないので結局よく分からない。

これで正しければこの上なく楽なのだが。

 

追記:

分かったわけではないけど、普通みたい。

eventキーワードで宣言した場合に限り、こういうシンタックスシュガーみたいなことができるのだと、今のところは解釈している。

Visual Studio 2008のエディションごとの機能比較

Microsoft Visual Studio 2008 製品ラインの概要

よく知らないうちはStandardとProfessionalの違いがよく分からなかったんだけど、いろいろな機能を使えるようになってくると、無いと困るものも出てくる。次期バージョンを買う際には参考にしたい。

これから使う予定の機能が多いので、使って公開するかもしれないけれど。

  • Crystal Reports(いるでしょ?)
  • 単体テスト(うーん。使いたいけど。当分使えないかも。)
  • Officeアプリケーション開発(いる?かもなあ。。。)
  • モバイルデバイスサポート(そんのに手出してる余裕ないわ。)
  • SQLデバッグ(そんな機能あったっけ?あるとしてもSQL Serverしか対応してないよね。)

Windows Serviceアプリケーションの開発

最初にC#に触れてから1年近くが経とうとしているが、3ヶ月ほど前から本格的なシステムの開発を始めた。そういうわけでいろいろなところでつまづきまくっている。今回はWindowsサービスアプリケーションの開発。何とか道が見えたところで、記憶にとどめておくべきことをメモしておきたい。

クリティカルな部分をサービスに切り出して、必要なときだけGUIを立ち上げればよいような構造にしている。ゼロからの開発になるので、サービス・GUI・クラスライブラリを全部1つのソリューションの中で管理している。

サービスアプリ自体の開発はいったんやり方を見つければ簡単なんだけど、そこに行き着くまでが大変だった。ウェブ上にも古いやり方しか載っていない。installutil.exeとかコマンドラインツールを使う方法は古い。普通のアプリと同じ方法でセットアッププロジェクトを作ったあと、カスタム動作を設定するだけだ。このカスタム動作の設定の仕方は次のとおり。

1. ソリューションエクスプローラから、セットアッププロジェクトを右クリック->表示->カスタム動作

2. 開いた画面で、カスタム動作アイコンを右クリック->カスタム動作の追加

3. 開いたダイアログで、アプリケーションフォルダをダブルクリック。
 

4. アプリケーションのプライマリ出力を選択してOK。

5. 2の画面の各アクションにプライマリ出力が追加される。各アクション(イベント)のコールバックはProjectInstaller.csに自動的に実装される。
 

私は、これにインストール時に起動、アンインストール時に停止するアクションを加えた。ProjectInstallerのデザイナのイベントプロパティから、AfterInstall, BeforeUninstallイベントハンドラを追加する。ソース全体は以下のようになった。

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.ServiceProcess;
using System.Windows.Forms;


namespace SignalService
{
    [RunInstaller(true)]
    public partial class ProjectInstaller : Installer
    {
        public ProjectInstaller()
        {
            InitializeComponent();
        }

        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);
        }

        public override void Commit(IDictionary savedState)
        {
            base.Commit(savedState);
        }

        public override void Rollback(IDictionary savedState)
        {
            base.Rollback(savedState);
        }

        public override void Uninstall(IDictionary savedState)
        {
            base.Uninstall(savedState);
        }

        private void ProjectInstaller_AfterInstall(object sender, InstallEventArgs e)
        {
            ServiceController controller = new ServiceController(serviceInstaller1.ServiceName);
            controller.Start();
        }

        private void ProjectInstaller_BeforeUninstall(object sender, InstallEventArgs e)
        {
            ServiceController controller = new ServiceController(serviceInstaller1.ServiceName);
            try
            {
                controller.Stop();
            }
            catch (Exception)
            {
            }
        }
    }
}

過去にうちの先輩がC++で開発した、リモートデバッグ機能付きのロギングDLLを使おうとしたのだが、実はサービスアプリケーションで使うのは初めてだった。DllImportして使うわけだが、サービスが起動しているときに、GUIからもこのDLLを呼ぶと、System.DllNotFoundExceptionが発生する。サービスでなければ2つのアプリケーションから同時に使うことは問題なかったので、多分ユーザ権限の問題なのだろう。サービスはLocalSystemで動作させていた。このDLL特有の問題なのかもしれない。

また、ログファイルの出力先をカレントディレクトリのlogフォルダ(“.log”)としていたのだが、なぜかファイルが書かれない。絶対パスを指定するとちゃんと書かれるので、Program Filesに書くには特別な権限が必要なんだろうかと想像したりもしたが、デバッガをアタッチしてみると、実は単にカレントディレクトリが C:WINDOWSsystem32 になっていることが分かった。そこには普通にログが書き出されていた。以下のようにカレントディレクトリを移動することで解決した。

        private void MoveCurrentDirectory()
        {
            Assembly exe = Assembly.GetEntryAssembly();
            FileInfo exeFileInfo = new FileInfo(exe.Location);
            Directory.SetCurrentDirectory(exeFileInfo.DirectoryName);
        }

結局このDLLはサービスで使うと他で使えないようだったので、サービス用のロガーはC#で書いた。たいした機能はないが、キューイングして別スレッドで遅延書き込みみたいなことを実装した。リモートデバッグはとりあえず、Debug.Printで我慢する。