じゃんぬのどっとてきすと

雑記とネタと時々プログラミング

ホーム 連絡をする 同期する ( RSS 2.0 ) Login
投稿数  982  : 記事  4  : コメント  16193  : トラックバック  277

ニュース

My Website

初心者向けのサイトです。

C# と VB.NET の入門サイト

最近のできごと

少し前に女のコが生まれました。家事と育児と仕事にと奮起しています。めちゃくちゃかわいいです。あと Blog の更新は全然してませんが、Twitter とかでアホなこと呟いています。見つけることができたら、ぜひフォローしてあげてください。けっこう喜びます。

Sponsored Link1

Sponsored Link2

Archive

書庫

前回の記事で、VB6.0 で「Form の既定のインスタンス」を防ぐ方法について書きました。

VB2005 (VB8) で、Form の既定のインスタンス (Form の暗黙的なインスタンス化) が復活してしまったので、それを防ぐ方法を考えたいと思います。

デフォルトでは、以下のようにコードから「Form の既定のインスタンス」の実体である、My.Forms 配下にアクセスできます。

My.Forms (Form の既定のインスタンス) にアクセス可能

My.Forms (Form の既定のインスタンス) にアクセス可能

できれば「コンパイル解決」したいので、いっそ使えなくしてしまいましょう。vbproj ファイルを、テキスト エディタなどで開いてみてください。

変更前の vbproj ファイル

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>8.0.50727</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{????????-????-????-????-????????????}</ProjectGuid>
    <OutputType>WinExe</OutputType>
    <StartupObject>Sub Main</StartupObject>
    <RootNamespace>WindowsApplication1</RootNamespace>
    <AssemblyName>WindowsApplication1</AssemblyName>
    <MyType>WindowsForms</MyType>
    <MyType>WindowsFormsWithCustomSubMain</MyType>
  </PropertyGroup>

<PropertyGroup> 要素内に <MyType> 要素があります。<MyType> 要素の中身は、アプリケーション フレームワークが有効である場合は "WindowsForms" が、そうでない場合は "WindowsFormsWithCustomSubMain" が格納されています。この <MyType> 要素の中身を、次のように "Empty" に変えます。

Form の既定のインスタンスと My を防いだ状態の vbproj ファイル

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>8.0.50727</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{????????-????-????-????-????????????}</ProjectGuid>
    <OutputType>WinExe</OutputType>
    <StartupObject>Sub Main</StartupObject>
    <RootNamespace>WindowsApplication1</RootNamespace>
    <AssemblyName>WindowsApplication1</AssemblyName>
    <!-- <MyType>WindowsForms</MyType> -->
    <!-- <MyType>WindowsFormsWithCustomSubMain</MyType> -->
    <MyType>Empty</MyType>
  </PropertyGroup>

こうすることで、My 自体の使用を防ぐことができます。その結果、Form の既定のインスタンスの使用も防ぐことができるわけです。

My.Forms (Form の既定のインスタンス) にアクセス不可

My.Forms (Form の既定のインスタンス) にアクセス不可

My 自体の使用を禁じると、プロジェクトのプロパティにある「アプリケーション フレームワークを有効にする」が非活性になることに注意してください。

「アプリケーション フレームワークを有効にする」が非活性になる

「アプリケーション フレームワークを有効にする」非活性になる

Form の既定のインスタンスの使用だけを封じて、My が使用できるようにするには以下のようにします。ただし、この方法ですとコンパイル解決 (コンパイル時にチェック) することができません。

VB2005 - フォームの「既定のインスタンス」の使用を実行時に防ぐ

Option Strict On

Public Class Form2

    Public Sub New()
        ' この呼び出しは、Windows フォーム デザイナで必要です。
        Me.InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。
        AddHandler Me.HandleCreated, Addressof Form_HandleCreated
    End Sub

    Private Shared Sub Form_HandleCreated(ByVal sender As Object, ByVal e As System.EventArgs)
        If sender Is My.Forms.Form2 Then
            Throw New System.InvalidOperationException("既定のインスタンスを使用するんじゃあないッ!!")
        End If
    End Sub

End Class

既定のインスタンスと同一のインスタンスであった場合は、InvalidOperationException 例外をスローします。

引数 sender とのインスタンス比較に、My.Forms コレクション内のメンバを使っているのは、こちらの方が '型 (Form2)' との区別がついて見やすいからです。既定のインスタンスの実体 (Form2) は、My クラスの Forms コレクションのメンバ (My.Forms.Form2) と同一になります。

VB2005 (VB8) では、同じ型のインスタンス内から、フォームの既定のインスタンスを参照することができません。そのため、HandleCreated イベントのシグネチャが、共有メンバ (Shared メンバ) になっています。

これでは、わざわざすべての Form クラスに記述が必要になってしまい、実用的ではありません。ですから、次のようにリフレクションを使って実装した方が実用的であると言えます。リフレクションを使って動的にイベントを関連付けていますので、アセンブリ (プロジェクト) にどれだけフォームを追加したとしても問題ありません。

VB2005 - フォームの「既定のインスタンス」の使用を実行時に防ぐ (リフレクション版)

Option Strict On

Public Class Program

    ' エントリ ポイント
    <System.STAThread()> _
    Public Shared Sub Main()
        ' フォームの「既定のインスタンス」をすべて HandleCreated イベント ハンドラへ動的に追加
        AddHandlerFormsHandleCreated()

        ' アプリケーションを Form1 から開始する
        System.Windows.Forms.Application.Run(New Form1())
    End Sub

    ' すべての「既定のインスタンス」の HandleCreated イベントを設定
    Private Shared Sub AddHandlerFormsHandleCreated()
        Dim oType       As System.Type = GetType(My.MyProject.MyForms)
        Dim oProperties As System.Reflection.PropertyInfo() = oType.GetProperties()

        For Each oProperty As System.Reflection.PropertyInfo In oProperties
            Dim oObject As Object = oProperty.GetValue(My.MyProject.Forms, Nothing)

            If TypeOf oObject Is System.Windows.Forms.Form Then
                Dim oForm As System.Windows.Forms.Form = DirectCast(oForm, System.Windows.Forms.Form)
                AddHandler oForm.HandleCreated, AddressOf Forms_HandleCreated
            End If
        Next oProperty
    End Sub

    ' すべての「既定のインスタンス」の HandleCreated イベント
    Private Shared Sub Forms_HandleCreated(ByVal sender As Object, ByVal e As System.EventArgs)
        Throw New System.InvalidOperationException("既定のインスタンスが使用されました。")
    End Sub

End Class

VB の言語設計者は "フォームは、単一のインスタンスである場合が多い" ことを理由に「既定のインスタンス」を復活させました。しかし、どこからでもアクセスできるのは、(特にグループ開発のことを考えて) デメリットでもあるという点も考慮して欲しかったです。既定のインスタンスを設けること自体には、もはや反対はしませんが、プロジェクトのプロパティなどで「既定のインスタンスの使用を禁止する」というオプションがあっても良いのではないでしょうか?

Microsoft Connect : Visual Studio and .NET Framework (Product Feedback Center) に、以下のようなフィードバックがあります。

Do not re-introduce the default instance of a Form! (microsoft.com) からの引用

The removal of the default instance in the initial versions of .NET was a bold move, but one that *should* have been done.
So why re-introduce them ?
They helped a little in getting newbies started, but this caused no end of hard-to-debug problems later on, and a lot of professional developers generally attempt to remove any use of them when touching the resulting code, or refuse to touch the code altogether.

意訳しますと「既定のインスタンスを再導入しないでください!!」と訴えているわけですね。さらには、255 人もの方が高いレートで Vote しています。(平均 4.62 Rate)

これとは別に「プロジェクトのプロパティなどで '既定のインスタンスの使用を禁止する' というオプションを設けてください」というフィードバックをしようかと迷っています。皆さん、投票してくれるでしょうか... (;^-^)

投稿日時 : 2006年10月26日 9:45

コメント

# re: VB2005 で Form の「既定のインスタンス」(暗黙のインスタンス化) を防ぐには? 2006/10/26 10:25 まどか
まったくもって、「インスタンス」の概念が脳から消え去るので、禁止派ですが
回避する方法を考えてみたものの、脳が大混乱しますね。。。

オプションもいいけど、異なるスコープで使用されていたら警告出すとか。
馬の耳に念仏か。

# re: VB2005 で Form の「既定のインスタンス」(暗黙のインスタンス化) を防ぐには? 2006/10/26 10:28 じゃんぬ
>まどか さん
"異なるスコープで使用されていたら" とは、何でしょうか?
もともと同クラス内では、Me しか使えませんよ。
それ以外のところがすべて NG だとすれば、完全禁止と同義です。

# re: VB2005 で Form の「既定のインスタンス」(暗黙のインスタンス化) を防ぐには? 2006/10/26 16:29 まどか
あ、スコープという言葉がまずいですね。。。
プロシージャ内のように閉じられた世界ではなくあっちゃこっちゃで使ってたら
「正しく動作しないかもよ」っていう警告です。
って閉じられた世界もへったくれも無いですね。>よく考えたら意味無い

# re: VB2005 で Form の「既定のインスタンス」(暗黙のインスタンス化) を防ぐには? 2006/10/26 19:37 未記入
暗黙のインスタンス化が嫌いでC#を選ぶ人が増えそうだね。

# re: VB2005 で Form の「既定のインスタンス」(暗黙のインスタンス化) を防ぐには? 2006/10/26 20:06 R・田中一郎
僕も、オプションを設けるというのが最も良い妥協点だと思います。
結局 VB は、裾野の広い言語でいたいということなのでしょうから。

# re: VB2005 で Form の「既定のインスタンス」(暗黙のインスタンス化) を防ぐには? 2006/10/26 21:55 うじはら
暗黙のインスタンス化は、VB6 からの移行が順調に進まないため、互換性を高めることが最大の目的なのでしょう。また、小さいプログラムの場合は、こちらの方が便利なように思います。
VBは、C++やJavaのような強い型付けの言語ではなく、PerlやPythonのような言語を目指しているように見えます。C# と構文だけ異なると揶揄されるような言語では、将来、存在意義が問われますからね。

# re: VB2005 で Form の「既定のインスタンス」(暗黙のインスタンス化) を防ぐには? 2006/10/26 22:19 じゃんぬ
> VBは、C++やJavaのような強い型付けの言語ではなく、
> PerlやPythonのような言語を目指しているように見えます。

そんなことはないと思いますよ。
Option Strict の存在からして両方できるという広さが目標でしょう。

> C# と構文だけ異なると揶揄されるような言語では、
> 将来、存在意義が問われますからね。

まともに使っているとすれば、それでも良いと思います。
VB のクセがついてしまうと、これはこれで良いと思えるものです。
今なら、COM Interop 系が得意というおまけはありますが。

# re: VB2005 で Form の「既定のインスタンス」(暗黙のインスタンス化) を防ぐには? 2006/10/27 14:42 NAKA Hirotoshi.
> VBは、C++やJavaのような強い型付けの言語ではなく、
> PerlやPythonのような言語を目指しているように見えます。

あんまりそんな風に考えてるとC#もあっさり変わってがっくりくるよ。
スタティックな、ダイナミックな、ファンクショナルなすべての方向に翼を広げていくことは明白。

# re: VB2005 で Form の「既定のインスタンス」(暗黙のインスタンス化) を防ぐには? 2006/10/27 16:44 かるあ
> これとは別に「プロジェクトのプロパティなどで '既定のインスタンスの使用を禁止する' というオプションを設けてください」というフィードバックをしようかと迷っています。
> 皆さん、投票してくれるでしょうか... (;^-^)

投票します。


# re: VB2005 で Form の「既定のインスタンス」(暗黙のインスタンス化) を防ぐには? 2006/10/29 23:24 アクア
かるあさんに同じく。

# Form の「既定のインスタンス」を禁止できるオプションが欲しい 2006/11/16 10:43 じゃんぬねっと日誌
Form の「既定のインスタンス」を禁止できるオプションが欲しい

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2006/12/31 17:31 ハッカ飴
否定だけで代替案が示されないと
それで?
という印象しか受けません。
フォームのインスタンス数を制限したい場合はどうするのでしょう。
シングルトンの実装も併記されてはいかがでしょうか。

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2007/01/01 23:05 じゃんぬねっと
どうも、記事の内容が理解されていないようです。

> 否定だけで代替案が示されないと
> それで?
> という印象しか受けません。
普通、'良くない' と思うことを改善するにあたり、代替案など設けません。
既定のインスタンス自体が望ましくない場合というテーマですから、代替案というのはヘンでしょう。
(何のための対策なのか、理解されていないのではないでしょうか)

> フォームのインスタンス数を制限したい場合はどうするのでしょう。
個人的には「制限したい」という設計自体がいかがなものかと思います。
それとも、シングルトンという意味でしょうか。(でしたら、単一のインスタンスと書きましょう)

> シングルトンの実装も併記されてはいかがでしょうか。
デザイン パターンがすべて良いものであると考えているのでしょうか?
デザイン パターンの中には、グループ開発上 (業務アプリケーション上) 苦肉の策で設けているパターンも存在します。
シングルトンもその中のひとつと言われていますし、私もそう考えています。

というより、、、'ここまでの内容が正しいか間違っているかを抜きに考えても' ですが、

『シングルトンで代用するくらいならば、
 '最初から' 既定のインスタンスを使えば良いでしょう。』

と、声を大にして言いたくなるようなご発言で、記事の内容をご理解していないと判断せざるをえません。

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2007/01/05 23:26 なんか。。。
頭の悪い人が1人紛れ込んだみたいですね。
無知なのは悪いことじゃないですが、無知なゆえ本質が理解できず「それで?」というのは、失礼極まりないでしょう。
そんな相手にまで、わざわざ説明するなんてお優しいですね。

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2007/01/16 22:01 こんなところにまで・・
ハッカ飴って有名なキチガイですよ。
相手にしちゃダメです。

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2007/02/20 17:35 すけけん
VB2005を勉強しているものです。
「Form の既定のインスタンス」を無効にするもうひとつの方法を見つけました。

vbprojファイル内の
<MyType>WindowsForms</MyType>
の部分はそのままで
同じ<PropertyGroup>要素内に以下を追加

<DefineConstants>_MyType="Custom",_MYAPPLICATIONTYPE="WindowsForms",_MYCOMPUTERTYPE="Windows",_MYUSERTYPE="Windows",_MYFORMS=false</DefineConstants>

これでMy.Formsが無効になり、アプリケーション フレームワークを有効にする」が非活性になりませんでした。
これってどうですかね?

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2007/02/20 18:22 じゃんぬねっと
>すけけん さん
これは知らなかったです。
ピンポイントで My.Forms をターゲットにしているのは良いですね!
こちらの方が効果がわかりやすいです。

このネタを使わせて頂けないでしょうか?
よろしくお願いします。

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2007/02/20 18:43 すけけん
早速の返答ありがとうございます。

ぜひ使ってください!

今VB2005を勉強していて、丁度My名前空間についてやっていて発見して、思わず投稿しましたw

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2007/02/20 18:59 じゃんぬねっと
>すけけんさん
ありがとうございます。

しかし、これは偶然発見できるようなものでもなさそうですよね。
ピンポイントで調べないとなかなか...

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2007/02/20 20:42 すけけん
はい、偶然みつけたってわけではないです。
説明するとちょっと長いですが。。

VisualBasic2005言語編(下)のMy名前空間について載っている章があり、
その中で、コンパイル定数によるカスタマイズというのを読みました。

そこには詳細コンパイルオプションのコンパイル定数のカスタム定数に<DefineConstants>タグでくくった文字列を設定するとカスタマイズできるとなっていました。

あいにく、自分の環境がExpressEditionで試せなかったため、.NET2003のカスタム定数にあたるDefineConstantsをvb2005のプロジェクトファイルに追加したらできましたw

なのでExpressEdition以外ならもっと簡単にできるかもしれません。

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2007/02/21 9:12 じゃんぬねっと
コンパイル オプションのカスタム定数に書き込めば OK みたいですね。
IDE から設定できるとなると、より一層重宝しそうです。

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2007/02/21 9:33 じゃんぬねっと
このままですと、My.WebServices が使用できないようなのでちょっと調べてみました。
カスタム定数に _MyWebServices=True も加えることで My.Forms だけを封じることができそうです。

ということで、これで紹介させて頂きますね。

_MyType="Custom",
_MyApplicationType="WindowsForms",
_MyComputerType="Windows",
_MyUserType="Windows",
_MyForms=False,
_MyWebServices=True

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2007/02/21 9:52 すけけん
My.WebServicesまで気が回ってませんでした(^^;

_MyType="Custom"とした場合、
他を省略するとそれに該当するオブジェクトが
作られなくなるみたいですね。
なので

_MyType="Custom",
_MyApplicationType="WindowsForms",
_MyComputerType="Windows",
_MyUserType="Windows",
_MyWebServices=True

これでもでいけました。

よろしくお願いいたします。

# re: VB2005 で「Form の既定のインスタンス」と My の使用を防ぐには? 2007/02/21 10:03 じゃんぬねっと
お返事ありがとうございます。

> これでもでいけました。

そうですね、省略すると False になるみたいですね。
一応明示的にという意味で、False と書いた方が良いかもしれません。

# VB のコーディング規約 (標準) に意義あり 2007/03/22 10:20 じゃんぬねっと日誌
VB のコーディング規約 (標準) に意義あり

# re: どうにもVBが好きになれない 2008/06/04 19:16 東方算程譚
re: どうにもVBが好きになれない

# tajuPfquYYeKZnj 2014/08/07 8:14 http://crorkz.com/
EUxXgr Thanks for sharing, this is a fantastic blog post.Really looking forward to read more. Fantastic.

Post Feedback

タイトル
名前
Url:
コメント: