カテゴリー: VB.NET

  • [VB.NET]プロパティの定義方法

    VB.NETでは、オVB.NETで学ぶプロパティの基本と応用:GetterとSetterの完全ガイド
    プログラミングにおいて、オブジェクト指向(OOP)は非常に重要な考え方の1つです。そして、その中心的な概念のひとつが「カプセル化」です。カプセル化とは、データ(フィールド)への直接的なアクセスを避け、メソッドやプロパティを通じて安全にやり取りする仕組みを意味します。
    この記事では、VB.NETにおけるプロパティ(Property)の使い方について、実際のコード例を交えながら詳しく解説します。特に、GetterとSetterを使ったプロパティの実装方法、読み取り専用や書き込み専用のプロパティの使いどころまで掘り下げていきます。初心者の方にも理解しやすい内容になっていますので、ぜひ最後までご覧ください。


    1. プロパティとは?

    まず、プロパティの定義から見ていきましょう。プロパティは、クラス内部のフィールド(データ)に対して、外部からアクセスできるようにする「窓口」のようなものです。

    フィールドとの違いは?

    以下のように、フィールドに直接アクセスするのは基本的に推奨されません:

    Public Class Person
        Public Name As String
    End Class
    
    Dim person As New Person()
    person.Name = "Alice"  ' フィールドに直接アクセス

    このような直接的なアクセスでは、後からロジックを追加したり、データの検証をしたりするのが難しくなります。そこで登場するのがプロパティです。プロパティを介することで、内部構造を隠しながら、必要に応じてアクセス方法を柔軟に制御できます。


    2. Getterの定義

    Getterとは、プロパティの値を取得するための機能です。まずは読み取り専用のプロパティの例を見てみましょう。

    Public Class Person
        Private _name As String
    
        Public Sub New(name As String)
            _name = name
        End Sub
    
        Public ReadOnly Property Name As String
            Get
                Return _name
            End Get
        End Property
    End Class
    

    このコードでは、_nameというプライベートな変数を外部から直接見えないようにしつつ、Nameプロパティを通じて安全に値を取得できるようにしています。

    呼び出し側のコードは次の通りです:

    Dim person As New Person("Alice")
    Console.WriteLine(person.Name) ' "Alice"と表示される

    このように、プロパティを使うことで内部のデータ構造を隠しつつ、必要な情報だけを提供することができます。


    3. Setterの定義

    Setterとは、プロパティの値を外部から**設定(代入)**できるようにするための構文です。以下のように、GetterとSetterを両方定義することで、読み書き両方に対応したプロパティを作成できます。

    Public Class Person
        Private _name As String
    
        Public Property Name As String
            Get
                Return _name
            End Get
            Set(value As String)
                _name = value
            End Set
        End Property
    End Class
    

    これを使えば、次のように値の取得も設定も可能になります:

    Dim person As New Person()
    person.Name = "Bob" ' Setterを使って値を変更
    Console.WriteLine(person.Name) ' "Bob"と表示される

    このように、Setterを使えば、値を設定する際に検証処理を入れるなどの柔軟な対応が可能になります。


    4. ReadOnly・WriteOnlyプロパティ

    VB.NETでは、読み取り専用(ReadOnly)や書き込み専用(WriteOnly)のプロパティも定義できます。用途に応じて使い分けましょう。

    読み取り専用プロパティ

    Public ReadOnly Property Name As String
        Get
            Return _name
        End Get
    End Property

    このようにGetterのみを持つプロパティは、外部からの値の変更を禁止できます。

    書き込み専用プロパティ

    Private _password As String
    
    Public WriteOnly Property Password As String
        Set(value As String)
            _password = value
        End Set
    End Property

    こちらは、セキュリティ上重要な情報(例:パスワード)などでよく使用されます。値の設定は許可しますが、取得は不可です。


    5. 自動実装プロパティ(Auto-Implemented Property)

    VB.NETでは、より簡潔にプロパティを定義する自動実装プロパティという構文もあります。以下のように記述できます:

    Public Property Name As String

    この場合、コンパイラが内部的にフィールドとGetter/Setterを自動生成してくれます。ロジックが不要な場合に便利です。


    6. プロパティにロジックを追加する

    プロパティには単に値を返すだけでなく、ロジックを組み込むことも可能です。たとえば、名前の入力が空文字列やNullの場合に例外を投げるようにできます。

    Public Property Name As String
        Get
            Return _name
        End Get
        Set(value As String)
            If String.IsNullOrWhiteSpace(value) Then
                Throw New ArgumentException("名前を空にすることはできません。")
            End If
            _name = value
        End Set
    End Property

    これにより、誤った値の代入を未然に防げます。


    7. プロパティの活用例:ログ付きプロパティ

    例えば、変更のたびにログを出力するようなプロパティも以下のように実装できます:

    Private _age As Integer
    
    Public Property Age As Integer
        Get
            Return _age
        End Get
        Set(value As Integer)
            Console.WriteLine($"年齢を{_age}から{value}に変更します")
            _age = value
        End Set
    End Property

    8. まとめ

    プロパティは、VB.NETにおけるオブジェクト指向の核となる要素の1つです。適切に使うことで、クラスの内部構造を外部に隠しながら、安全で柔軟なデータ操作を実現できます。

    本記事のまとめポイント:

    • Getter は値を取得するための構文
    • Setter は値を設定するための構文
    • ReadOnly プロパティは外部からの変更を禁止したいときに便利
    • WriteOnly プロパティは機密情報などの取得を防ぎたいときに使う
    • 自動実装プロパティは簡潔にプロパティを定義したいときに使える
    • ロジック入りのプロパティでバリデーションやログ出力も可能

    プロパティの使い方を正しく理解することで、より保守性の高い、信頼性のあるコードを書くことができます。ぜひ、今後のVB.NETの開発において積極的に活用してみてください。

  • VB.NETでフォーム開発時のデザイナーエラーとDesignModeチェックの活用法

    VB.NETでWindowsフォームアプリケーションを開発していると、「デザイナーでフォームを開こうとしたらエラーが出て表示できない」といったトラブルに遭遇することがあります。このようなエラーの多くは、フォームやコントロールが外部リソース(データベース、ファイル、APIなど)に依存している場合や、実行時にしか利用できないオブジェクトにアクセスしているケースで発生します。

    このようなときに役立つのが、VB.NETのDesignModeプロパティを使った「デザインモードの判定」です。この記事では、DesignModeの使い方からその有効性、そして根本的なデザイナーエラーの解決策について、具体例を交えながら解説していきます。


    1. DesignModeとは?

    DesignModeプロパティは、現在のフォームやコントロールがVisual Studioのフォームデザイナー上で開かれているかどうかを判定するためのプロパティです。これを利用することで、デザイナー上でだけエラーになるような処理をスキップすることができます。

    たとえば、フォームのLoadイベント内でデータベース接続処理があると、デザイナーでは実行時の環境が整っていないために例外が発生してしまいます。以下のように、DesignModeを使ってこのような処理を制御することができます。

    Private Sub Form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        If Not Me.DesignMode Then
            ' 実行時のみ実行する処理
            LoadDataFromDatabase()
        End If
    End Sub

    このようにすることで、デザイン時には処理をスキップし、実行時だけ安全に動作させることが可能になります。


    2. なぜDesignModeチェックが必要なのか?

    DesignModeを使う主な理由は、デザイナー上での例外を回避してフォームの編集を可能にするためです。デザイナーは基本的に実行環境とは異なるため、依存リソースが存在しない、初期化されていないといった状態でフォームを表示しようとします。

    その結果、以下のような状況でエラーが発生することがあります。

    • 外部ファイルを読み込もうとしたが、デザインモードでは存在しない
    • データベースに接続しようとして例外が発生
    • サービス呼び出しが行われてタイムアウト
    • コンストラクタで未初期化のオブジェクトにアクセスしてしまう

    これらを防ぐために、DesignModeを使ってデザインモードか実行モードかを判定し、必要な処理だけを安全に実行することが求められます。


    3. DesignModeチェックの限界と注意点

    DesignModeによるチェックは非常に便利ですが、完全な解決策ではありません。以下のような制約や限界があります。

    3.1 正しく判定できないことがある

    DesignModeプロパティはComponentクラス(フォームやコントロールの基底)に存在していますが、実際には子コントロールなどでは正しく動作しない場合があります。特にUserControlの中でDesignModeをチェックしても、期待通りに判定されないケースがあります。

    そのため、以下のような独自判定ロジックを使うことが推奨される場合もあります。に移動することでエラーを回避できる場合があります。

    Public Function IsDesignMode(control As Control) As Boolean
        Dim site = control.Site
        Return site IsNot Nothing AndAlso site.DesignMode
    End Function

    3.2 根本原因を解決しない

    DesignModeチェックはあくまで**「例外の回避策」**であり、フォームやクラスの設計上の問題(過剰な依存、初期化の失敗など)を解決するわけではありません。


    4. 根本的な解決方法

    DesignModeを使わなくてもエラーが起きないように、設計段階で適切にコードを分離し、依存関係を管理することが理想的です。以下のようなアプローチで、デザイナーエラーの根本的な解決を目指しましょう。

    4.1 コンストラクタと初期化処理の見直し

    フォームのコンストラクタやLoadイベントで外部リソースを直接使うのは避け、InitializeComponentの後に明示的に初期化処理を分けて呼び出す設計が効果的です。

    Public Sub New()
        ' フォームの初期化
        InitializeComponent()
        ' 依存リソースの初期化は必要に応じて分離
        If Not Me.DesignMode Then
            InitializeResources()
        End If
    End Sub

    (4.2 実行時専用ロジックの分離

    外部接続処理やファイルアクセスなどは、可能な限り実行時だけに限定し、Viewとロジックを分離しましょう。MVPやMVVMなどの設計パターンを活用することで、ロジックをテストしやすく、保守性の高いコードが書けます。

    4.3 親子クラス間の依存関係の整理

    親クラスと子クラスのイベント処理や依存関係が複雑になっていると、デザイナーが正しく継承チェーンをたどれずエラーになることがあります。以下のようにMyBaseを使って親クラスの処理を明示的に呼び出すことで、トラブルを回避できます。

    Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)
        ' 子クラスでの追加処理
    End Sub

    4.4 デザインモード用のスタブ・モックを活用

    どうしてもリソースに依存してしまう場合は、デザインモード専用のダミーデータやモックオブジェクトを使うのも有効です。たとえば、実際のデータベース接続をせずに、ハードコードされたテストデータを使って画面表示を確認することができます。

    If Me.DesignMode Then
        LoadMockData()
    Else
        LoadRealData()
    End If

    5. まとめ:DesignModeは補助、設計の見直しが本質

    VB.NETのDesignModeチェックは、デザイナーエラーの即時的な回避策として非常に便利です。しかし、最終的には設計そのものを見直し、依存関係の分離や初期化処理の整理によって、根本的にエラーを発生させない設計を目指すことが重要です。

    • DesignModeは例外を回避するための補助的な手段
    • デザインモードと実行モードの違いを意識した設計が重要
    • 依存性の注入や責務分離により保守性・安定性を高める
    • 必要に応じてスタブやモックで対応し、フォームの見た目を確認可能にする

    デザイナーエラーは、放っておくと開発効率を大きく損ないます。しかし、適切な設計と工夫によって、誰もが安全かつ快適にフォーム開発を行えるようになるのです。

  • [C#, VB.NET]環境変数を使用したコードの動作確認方法

    [C#, VB.NET]環境変数を使用したコードの動作確認方法

    【VB.NET / C#】ClickOnceと環境変数を使ったアプリ動作の切り替えと確認方法

    アプリケーション開発において、「環境変数」を利用してアプリケーションの挙動を制御するのは、非常に一般的な手法です。特に、アプリケーションのデプロイ方法(例:ClickOnceなど)や実行環境(開発用・本番用など)に応じて処理を分岐したい場合、環境変数はとても便利な仕組みになります。

    この記事では、ClickOnceを利用した.NETアプリケーションの挙動を環境変数で制御し、それをVB.NETおよびC#の両方で実装・確認する方法を、段階を追って解説していきます。


    🔍 この記事でわかること

    • 環境変数を使った.NETアプリの挙動切り替え方法
    • Visual Studioでの環境変数設定方法
    • VB.NET / C# の実装例と動作確認
    • ClickOnceを使った本番環境に近いテスト手法
    • ユニットテストでの環境変数モック手法
    • 環境変数を使う際の注意点

    🧪 なぜ環境変数を使うのか?

    たとえば、アプリケーションがClickOnceを使ってネットワークからインストールされて実行された場合、特定の処理(バージョン表示や、ログ収集など)を行いたいケースがあります。しかし、コード上で ApplicationDeployment.IsNetworkDeployed を直接使うと、ClickOnceを使わずに実行したときに例外が発生する恐れもあるため、柔軟な方法として「環境変数を使って動作を切り替える」という手法が活躍します。


    🧾 VB.NETでの実装例

    If Environment.GetEnvironmentVariable("ClickOnce_IsNetworkDeployed")?.ToLower() = "true" Then
        Dim version = Environment.GetEnvironmentVariable("ClickOnce_CurrentVersion")
        ' TODO: version情報があっているか確かめたい
       Version_System = "Ver." + version
    End If

    このコードは、環境変数 ClickOnce_IsNetworkDeployed"true" に設定されている場合にのみ、バージョン情報を取得し、それを Version_System に代入します。


    🧾 C#での実装例

    if (Environment.GetEnvironmentVariable("ClickOnce_IsNetworkDeployed")?.ToLower() == "true")
    {
        var version = Environment.GetEnvironmentVariable("ClickOnce_CurrentVersion");
        Version_System = "Ver." + version;
    }

    VB.NETとC#では構文こそ異なるものの、基本的なロジックは共通です。


    ✅ 開発中に動作を確認する方法

    1. Visual Studioで環境変数を設定する方法

    開発中に手軽に環境変数を設定する方法として、Visual Studioのプロジェクトプロパティから設定する方法があります。

    1. プロジェクトを右クリックし、「プロパティ」を開きます。
    2. 「デバッグ」タブを選択します。
    3. 「環境変数」の項目に以下を追加します:
      • ClickOnce_IsNetworkDeployed : true
      • ClickOnce_CurrentVersion : 1.0.0.0

    こうすることで、デバッグ実行時にこれらの環境変数がプロセススコープで適用され、コードで取得できるようになります。


    2. システム環境変数として設定(注意)

    Windowsの「システム環境変数」に設定することで、OS全体のプロセスから参照できるようにもできますが、これは開発中には推奨されません。誤って他のアプリに影響を与えてしまう可能性もあるため、基本はVisual Studioのデバッグ設定で十分です。


    3. デバッグとログ出力による確認

    以下のようにログをコンソール出力することで、環境変数が正しく設定され、意図通りの分岐がされているかを確認できます。

    VB.NET版ログ付きコード

    Dim isDeployed = Environment.GetEnvironmentVariable("ClickOnce_IsNetworkDeployed")?.ToLower()
    Console.WriteLine($"IsNetworkDeployed: {isDeployed}")
    If isDeployed = "true" Then
        Dim version = Environment.GetEnvironmentVariable("ClickOnce_CurrentVersion")
        Console.WriteLine($"CurrentVersion: {version}")
        Version_System = "Ver." + version
    Else
        Console.WriteLine("ClickOnce deployment is not detected.")
    End If

    C#版ログ付きコード

    var isDeployed = Environment.GetEnvironmentVariable("ClickOnce_IsNetworkDeployed")?.ToLower();
    Console.WriteLine($"IsNetworkDeployed: {isDeployed}");
    if (isDeployed == "true")
    {
        var version = Environment.GetEnvironmentVariable("ClickOnce_CurrentVersion");
        Console.WriteLine($"CurrentVersion: {version}");
        Version_System = "Ver." + version;
    }
    else
    {
        Console.WriteLine("ClickOnce deployment is not detected.");
    }

    4. ClickOnceによる本番形式のテスト

    実際にClickOnceでアプリケーションを発行し、インストールして実行することで、環境変数を自動で設定した状態での挙動も確認できます。ClickOnceでは、ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString() を使ってバージョンを取得できますが、これを環境変数に設定しておくことで、アプリケーションロジックからも取得可能になります。


    5. ユニットテストでの環境変数テスト

    ユニットテストで環境変数を使ったコードをテストするには、テスト実行前に Environment.SetEnvironmentVariable() を使って変数を設定できます。


    ⚠️ 環境変数を扱う際の注意点

    1. 大文字・小文字に注意
      環境変数はWindows環境では大文字小文字を区別しませんが、コード上の文字列比較では区別される可能性があります。.ToLower().Equals(x, StringComparison.OrdinalIgnoreCase) を使うのが安全です。
    2. nullチェックは必須
      指定した環境変数が存在しない場合、GetEnvironmentVariablenull を返します。これをそのまま使うと NullReferenceException が発生することがあるため、null条件演算子(?.)を使うか、明示的なnullチェックを行いましょう。
    3. 本番では別の設定方法も検討
      ClickOnce環境では環境変数よりも、アプリケーション設定ファイル(app.configuser.config)を利用することも検討できます。

    📝 まとめ

    環境変数を活用することで、開発と本番環境の違いに柔軟に対応でき、ClickOnceなどのデプロイ形式に応じた挙動制御が可能になります。VB.NETとC#のコードも非常に似ており、どちらでも同様の実装が行えます。

    開発中にはVisual Studioでの環境変数設定、ログ出力、ステップ実行、ユニットテストを活用し、確実に正しい動作を確認しましょう。


    📌 最後に

    環境に応じた設定をコードで判断できるようになると、より堅牢で柔軟なアプリケーションを構築できるようになります。ClickOnceや環境変数といった仕組みをうまく活用し、開発効率と信頼性を両立させていきましょう!

  • [VB.NET]代入演算とブール値の扱いについて

    こんにちは、今日はVB.NETでの代入演算子とブール値の扱いについて、特に次のコードがなぜエラーにならず、変数に-1が代入されるのかを詳しく解説します。

    hogehoge =
    fugafuga = 0

    なぜエラーにならないのか?

    一見すると、hogehoge =は代入する値がなく、不完全な文のように見えます。しかし、このコードはエラーにならずに実行されます。その理由は、VB.NETの代入演算子=が比較演算子としても機能するためです。

    代入演算子と比較演算子の両義性

    VB.NETでは、=代入演算子比較演算子の両方として使用されます。そのため、上記のコードは次のように解釈されます。

    比較演算の結果を代入する

    hogehoge = (fugafuga = 0)

    fugafuga = 0は、hogehoge1と等しいかどうかを評価する比較演算で、結果はTrueになります。その比較結果をhogehoge代入しています。

    ブール値が-1または0になる理由

    ブール値と整数の変換

    VB.NETでは、ブール値を整数型に変換すると以下のようになります。

    • True-1
    • False0

    これは、VB.NETの内部表現でTrueが全てのビットが1であるためです。16ビットの整数で見ると、全てのビットが1のときは2の補数表現で-1になります。

    具体的な例

    Dim hogehoge As Integer
    Dim fugafuga As Integer
    hogehoge = fugafuga = 0  ' hogehoge には -1 が代入される

    fugafugaは、特に値が代入されていないため、デフォルト値の0が代入されます。

    fugafuga = 0の比較結果はTrueになります。Trueは整数の-1に変換されるため、hogehogeに0が代入されます。

    暗黙的な型変換とOption Strict

    暗黙的な型変換

    デフォルトでは、VB.NETは暗黙的な型変換を許可しています(Option Strict Off)。そのため、ブール値から整数型への変換が自動的に行われ、エラーになりません。

    Option Strict Onの活用

    コードの安全性と可読性を高めるためには、Option Strict Onを使用することが推奨されます。これにより、暗黙的な型変換が禁止され、意図しない代入やバグを防ぐことができます。

    Option Strict On

    この設定を有効にすると、ブール値を整数型に代入する際には明示的な変換が必要になります。

    コードの明確化

    比較と代入を分ける

    おそらくタイプミスで保存されたコードではありますが、まじめにやるなら、コードの可読性を高めるために、比較と代入を分けて書くことをおすすめします。

    Dim isEqual As Boolean = (fugafuga = 0)
    hogehoge = Convert.ToInt32(isEqual)

    まとめ

    • 代入演算子=と比較演算子=の両義性:VB.NETでは=が代入と比較の両方に使われるため、意図しない動作をする可能性があります。
    • ブール値の整数変換True-1False0として扱われます。
    • 暗黙的な型変換のリスクOption Strict Onを使用して、暗黙的な型変換を防ぐことが推奨されます。
    • 明示的な変換の重要性:ブール値を整数として扱う場合は、明示的な変換を行うことで、コードの可読性と信頼性が向上します。

    最後に

    VB.NETでの代入や比較、型変換は柔軟性が高い反面、注意しないと思わぬバグの原因となります。コードを書く際には、Option Strict Onを活用し、明示的な型変換を心がけましょう。また、変数のデフォルト値や現在の値を常に確認することで、予期せぬ挙動を防ぐことができます。

    まあ、そもそもタイプミスでコードを読む限り、

    hogehoge = 0
    fugafuga = 0

    と書きたかったんだろうなあ~

  • [VB.NET,.NET8]DbContextを自動生成する

    Entity Framework Core(以下EF Core)は、C#を使ったアプリケーション開発で主に利用されるORM(Object-Relational Mapping)フレームワークです。通常、C#を使ってDbContextやエンティティクラスを自動生成しますが、VB.NETユーザーの方でも同様にDbContextを自動生成することができます。
    今回は、EF CoreでVB.NETをサポートするための「EntityFrameworkCore.VisualBasic」ライブラリを活用する方法についてご紹介します。

    1. EntityFrameworkCore.VisualBasicとは?

    EntityFrameworkCore.VisualBasicは、EF CoreでVB.NETをサポートするための拡張ライブラリです。これを利用することで、VB.NET環境でもC#と同様に、データベースのスキーマからDbContextやエンティティクラスを自動生成できるようになります。

    通常、EF Coreではdotnet efコマンドを使用してデータベースからコードを生成しますが、このライブラリをインストールすることで、VB.NETプロジェクトにおいても同じ操作が可能になります。

    2. 環境準備

    VB.NETプロジェクトでEF Coreを使うためには、いくつかの前提条件を整える必要があります。以下の手順に従って、プロジェクトを準備しましょう。

    必要なパッケージのインストール

    EF Coreのパッケージをインストール
    プロジェクトのパッケージマネージャーコンソール(Tools > NuGet Package Manager > Package Manager Console)で以下のコマンドを実行します。

    Install-Package Microsoft.EntityFrameworkCore
    Install-Package Microsoft.EntityFrameworkCore.SqlServer # SQL Serverを使う場合
    Install-Package Microsoft.EntityFrameworkCore.Tools

    EntityFrameworkCore.VisualBasicをインストール
    VB.NET用のEF Core拡張ライブラリを追加します。

    Install-Package EntityFrameworkCore.VisualBasic

    これで、VB.NET環境でEF Coreを利用する準備が整いました。

    3. DbContextの自動生成手順

    次に、DbContextやエンティティクラスを自動生成する手順を解説します。ここでは、SQL Serverデータベースを使用した例を取り上げます。

    1. データベース接続情報の設定

    最初に、データベース接続情報をappsettings.jsonに追加します。例えば、以下のようにSQL Serverの接続文字列を設定します。

    {
      "ConnectionStrings": {
        "DefaultConnection": "Server=YOUR_SERVER;Database=YOUR_DATABASE;Trusted_Connection=True;"
      }
    }

    YOUR_SERVERYOUR_DATABASEの部分は、実際のサーバー名やデータベース名に置き換えてください。

    2. DbContextとエンティティの自動生成

    パッケージマネージャーコンソールで、Scaffold-DbContextコマンドを使ってデータベースからコードを生成します。

    Scaffold-DbContext "Server=YOUR_SERVER;Database=YOUR_DATABASE;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -ContextDir Contexts -Context YourDbContextName -Language VB

    コマンド解説

    • Scaffold-DbContext : EF Coreが提供するコマンドで、データベースからDbContextとエンティティを生成します。
    • -OutputDir : 自動生成されるエンティティクラスを保存するディレクトリ(ここではModelsフォルダ)。
    • -ContextDir : 自動生成されるDbContextクラスを保存するディレクトリ(ここではContextsフォルダ)。
    • -Context : 生成されるDbContextクラスの名前(ここではYourDbContextNameとしています)。
    • -Language VB : VB.NET用のコードを生成することを指定します。

    コマンドを実行すると、指定したディレクトリにVB.NET形式のDbContextおよびエンティティクラスが自動生成されます。

    3. 生成されたコードの確認

    自動生成が完了すると、指定したディレクトリにYourDbContextName.vbやエンティティクラスが作成されます。これらのクラスはVB.NETコードで記述されており、EF Coreを使用したデータベース操作がすぐに行えるようになっています。

    例えば、以下のようなDbContextクラスが生成されるはずです。

    Public Partial Class YourDbContextName
        Inherits DbContext
    
        Public Sub New()
        End Sub
    
        Public Sub New(options As DbContextOptions(Of YourDbContextName))
            MyBase.New(options)
        End Sub
    
        ' 各エンティティをDbSetとして定義
        Public Overridable Property Products As DbSet(Of Product)
        Public Overridable Property Categories As DbSet(Of Category)
    
        Protected Overrides Sub OnModelCreating(modelBuilder As ModelBuilder)
            MyBase.OnModelCreating(modelBuilder)
        End Sub
    End Class
    

    これにより、VB.NETでDbContextやエンティティの管理ができるようになります。

    4. 最後に

    EntityFrameworkCore.VisualBasicを活用することで、VB.NETプロジェクトでもC#と同じようにEF Coreを利用してデータベースのスキーマからコードを自動生成できるようになります。これにより、VB.NET開発者は、より効率的にデータベース操作を行うことができ、C#に依存せずにORMの恩恵を受けることが可能です。

    この記事で紹介した手順を参考に、ぜひあなたのVB.NETプロジェクトでもEF Coreを導入してみてください。

  • [VB.NET]DataGridViewでボタン列やテキスト列をソートする方法

    こんにちは、今回はWindows Formsアプリケーションで、DataGridViewコントロールを使用している際に、ボタン列やテキスト列をヘッダークリックでソートする方法について解説します。特に、BindingList<T>をデータソースとして使用している場合の対処法も含めて詳しく説明します。

    ソート可能な BindingList を実装する方法

    以下に、BindingList<T> を拡張してソート機能を追加する方法を説明します。

    1. SortableBindingList クラスを作成する

    まず、BindingList<T> を継承し、ソート機能を実装した SortableBindingList<T> クラスを作成します。

    Imports System.ComponentModel
    Imports System.Reflection
    
    Public Class SortableBindingList(Of T)
        Inherits BindingList(Of T)
        Implements IBindingListView
    
        Private isSortedValue As Boolean
        Private sortDirectionValue As ListSortDirection
        Private sortPropertyValue As PropertyDescriptor
        Private originalList As List(Of T)
        Private filterValue As String
    
        Public Sub New()
            MyBase.New()
            originalList = New List(Of T)()
        End Sub
    
        Public Sub New(list As IList(Of T))
            MyBase.New(list)
            originalList = New List(Of T)(list)
        End Sub
    
        Protected Overrides ReadOnly Property SupportsSortingCore() As Boolean
            Get
                Return True
            End Get
        End Property
    
        Protected Overrides ReadOnly Property IsSortedCore() As Boolean
            Get
                Return isSortedValue
            End Get
        End Property
    
        Protected Overrides ReadOnly Property SortPropertyCore() As PropertyDescriptor
            Get
                Return sortPropertyValue
            End Get
        End Property
    
        Protected Overrides ReadOnly Property SortDirectionCore() As ListSortDirection
            Get
                Return sortDirectionValue
            End Get
        End Property
    
        Protected Overrides Sub ApplySortCore(prop As PropertyDescriptor, direction As ListSortDirection)
            sortPropertyValue = prop
            sortDirectionValue = direction
    
            Dim list As List(Of T) = Me.Items
    
            list.Sort(Function(x, y)
                          Dim value1 As Object = prop.GetValue(x)
                          Dim value2 As Object = prop.GetValue(y)
                          Dim result As Integer = Comparer.Default.Compare(value1, value2)
                          If direction = ListSortDirection.Descending Then
                              result = -result
                          End If
                          Return result
                      End Function)
    
            isSortedValue = True
            Me.OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, -1))
        End Sub
    
        Protected Overrides Sub RemoveSortCore()
            Me.Items.Clear()
            For Each item In originalList
                Me.Items.Add(item)
            Next
            isSortedValue = False
        End Sub
    
        ' フィルタリングをサポートするために IBindingListView を実装
        Public ReadOnly Property SupportsFiltering As Boolean Implements IBindingListView.SupportsFiltering
            Get
                Return True
            End Get
        End Property
    
        Public Property Filter As String Implements IBindingListView.Filter
            Get
                Return filterValue
            End Get
            Set(value As String)
                filterValue = value
                UpdateFilter()
            End Set
        End Property
    
        Private Sub UpdateFilter()
            Dim items = originalList.AsEnumerable()
    
            If Not String.IsNullOrEmpty(filterValue) Then
                ' 簡易的なフィルタリングの実装(例: "Name = 'Alice'")
                Dim parts = filterValue.Split("="c)
                If parts.Length = 2 Then
                    Dim propName = parts(0).Trim()
                    Dim propValue = parts(1).Trim().Trim("'"c)
    
                    Dim prop = TypeDescriptor.GetProperties(GetType(T))(propName)
                    If prop IsNot Nothing Then
                        items = items.Where(Function(x) prop.GetValue(x).ToString() = propValue)
                    End If
                End If
            End If
    
            Me.Items.Clear()
            For Each item In items
                Me.Items.Add(item)
            Next
    
            Me.OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, -1))
        End Sub
    
        ' 他のメンバーの実装は省略していますが、必要に応じて追加してください
    
        Public ReadOnly Property SupportsAdvancedSorting As Boolean Implements IBindingListView.SupportsAdvancedSorting
            Get
                Return False
            End Get
        End Property
    
        Public Sub ApplySort(sorts As ListSortDescriptionCollection) Implements IBindingListView.ApplySort
            Throw New NotSupportedException()
        End Sub
    
        Public Sub RemoveFilter() Implements IBindingListView.RemoveFilter
            Me.Filter = Nothing
        End Sub
    
        Public ReadOnly Property SortDescriptions As ListSortDescriptionCollection Implements IBindingListView.SortDescriptions
            Get
                Return Nothing
            End Get
        End Property
    End Class
    

    のクラスのポイント:

    • BindingList<T> を継承し、ApplySortCore メソッドをオーバーライドしてソート機能を実装しています。
    • IBindingListView インターフェースを実装してフィルタリング機能もサポートしています(必要に応じて)。
    • isSortedValuesortDirectionValuesortPropertyValue などのフィールドでソート状態を管理しています。

    2. SortableBindingList を使用する

    SortableBindingList<T> クラスを使用して、データソースを作成します。

    ' 例として Employee クラスを定義
    Public Class Employee
        Public Property EmployeeID As Integer
        Public Property Name As String
    End Class
    
    ' データを作成
    Dim employees As New SortableBindingList(Of Employee)()
    employees.Add(New Employee() With {.EmployeeID = 1, .Name = "Alice"})
    employees.Add(New Employee() With {.EmployeeID = 2, .Name = "Bob"})
    employees.Add(New Employee() With {.EmployeeID = 3, .Name = "Charlie"})
    
    ' DataGridView にデータソースをバインド
    DataGridView1.DataSource = employees
    

    3. DataGridView の設定

    列の SortModeAutomatic に設定します。

    ' 自動ソートを有効にする
    DataGridView1.Columns("EmployeeID").SortMode = DataGridViewColumnSortMode.Automatic
    DataGridView1.Columns("Name").SortMode = DataGridViewColumnSortMode.Automatic
    

    まとめ

    • BindingList<T>のソート: SortableBindingList<T>を実装して、ソート機能を持たせます。

    注意点:

    • データソースの選択: データソースがソートをサポートしているか確認し、必要に応じてカスタム実装を行います。
    • データの整合性: カスタムソートを実装する際、データの整合性に注意が必要です。
  • [VB.NET]動的なテーブル名を使用した単体テストの方法

    はじめに

    データベースの値を検証する単体テストを作成する際、テーブル名が動的に決まる場合はEntity Framework Core(EF Core)が使用できません。そのような状況で、どのようにテストコードを書けばよいのでしょうか。本記事では、ADO.NETを使用して動的なテーブル名でデータベースの値をチェックする方法を詳しく解説します。

    ADO.NETを使用したデータベースアクセス

    ADO.NETは、.NET Frameworkに組み込まれたデータアクセス技術で、データベースとの直接的なやり取りが可能です。EF CoreのようなORMを使用しないため、動的なテーブル名にも柔軟に対応できます。

    サンプルコードの解説

    以下に、動的なテーブル名を使用してデータベースの値を検証する単体テストコードを示します。

    Imports System.Data.SqlClient
    Imports Microsoft.VisualStudio.TestTools.UnitTesting
    
    <TestClass>
    Public Class DatabaseValueTest
    
        Private ReadOnly connectionString As String = "YourConnectionStringHere"
    
        <TestMethod>
        Public Sub TestDatabaseValue()
            Dim tableName As String = GetDynamicTableName() ' 動的にテーブル名を取得
            Dim query As String = $"SELECT TOP 1 * FROM [{tableName}] ORDER BY SomeColumn"
    
            Using connection As New SqlConnection(connectionString)
                Using command As New SqlCommand(query, connection)
                    connection.Open()
    
                    Using reader As SqlDataReader = command.ExecuteReader()
                        If reader.Read() Then
                            ' データの検証
                            Dim actualValue As Object = reader("ColumnName")
                            Dim expectedValue As Object = GetExpectedValue()
                            Assert.AreEqual(expectedValue, actualValue)
                        Else
                            Assert.Fail("レコードが存在しません。")
                        End If
                    End Using
                End Using
            End Using
        End Sub
    
        Private Function GetDynamicTableName() As String
            ' テーブル名を動的に取得するロジックを実装
            Return "YourDynamicTableName"
        End Function
    
        Private Function GetExpectedValue() As Object
            ' 期待される値を取得または計算
            Return "ExpectedValue"
        End Function
    
    End Class
    

    コードのポイント

    • Imports文System.Data.SqlClientMicrosoft.VisualStudio.TestTools.UnitTestingをインポートしています。
    • connectionString:データベースへの接続文字列を指定します。
    • GetDynamicTableNameメソッド:動的にテーブル名を取得します。
    • SQLクエリの作成SELECT TOP 1 * FROM [{tableName}] ORDER BY SomeColumnで一番上のレコードのみを取得します。今回は、一番上のレコードのみ検証したいため、これを入れています。
    • データの検証Assert.AreEqualを使用して、実際の値と期待される値を比較します。

    注意点とベストプラクティス

    SQLインジェクションの防止

    テーブル名はパラメータ化できないため、動的に生成する際には入力値を厳密に検証する必要があります。不正なテーブル名が入力されると、SQLインジェクション攻撃のリスクがあります。

    接続文字列の管理

    connectionStringにはデータベースへの正しい接続情報を設定してください。接続文字列は機密情報を含む場合が多いため、ソースコードに直接書き込まず、設定ファイルや環境変数から取得することをおすすめします。

    エラーハンドリング

    本番環境では、例外処理を適切に行い、接続やコマンドのリソースを確実に解放するように注意してください。Usingブロックを使用することで、自動的にリソースが解放されます。

    まとめ

    動的なテーブル名を使用した単体テストの実装方法について解説しました。ADO.NETを使用することで、EF Coreでは対応できないシナリオにも柔軟に対応できます。

    • ADO.NETの活用SqlConnectionSqlCommandSqlDataReaderを使用してデータベースにアクセス。
    • 一番上のレコードの取得SELECT TOP 1句とORDER BY句を組み合わせて特定のレコードを取得。
    • テストデータの管理:テスト用データベースやトランザクションを使用してテストの再現性を確保。
    • セキュリティ対策:動的なSQLを使用する際には、入力値の検証を徹底。

    今回の方法を活用して、より信頼性の高い単体テストを作成してみてください。

  • [C#,VB.NET]サポートされていないShift-JISエンコーディングのエラーとその解決方法

    はじめに

    .NET Coreや.NET 5+以降の環境で、Shift-JIS(日本語エンコーディング)を使用しようとすると、次のようなエラーが発生することがあります。

    System.ArgumentException: 'Shift-JIS' is not a supported encoding name.

    これは、.NET Coreや新しい.NETランタイムでは、Shift-JISなどの特定のエンコーディングがデフォルトではサポートされていないためです。しかし、CodePagesEncodingProviderを使用して、これらのエンコーディングを有効にすることができます。

    この記事では、C#とVB.NETでの解決方法を解説します。

    エラーの原因

    従来の.NET FrameworkではShift-JISエンコーディングがデフォルトでサポートされていましたが、.NET Coreや.NET 5+では軽量化とパフォーマンスの向上を目的に、デフォルトのエンコーディングサポートが制限されています。そのため、Shift-JISなどのコードページベースのエンコーディングを使用する場合は、明示的にサポートを有効にする必要があります。

    解決方法

    Step 1: CodePagesEncodingProviderの登録

    エンコーディングを有効にするために、アプリケーションの初期化時にCodePagesEncodingProviderを登録します。これにより、Shift-JISを含む多くのエンコーディングが利用可能になります。

    C#での実装

    C#では、次のようにしてShift-JISエンコーディングを有効にできます。

    using System;
    using System.Text;
    
    class Program
    {
        static void Main(string[] args)
        {
            // CodePagesEncodingProviderを登録してShift-JISを有効にする
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
    
            // Shift-JISエンコーディングを取得
            Encoding encoding = Encoding.GetEncoding("Shift-JIS");
    
            // 以下でShift-JISエンコーディングが利用可能です。
        }
    }
    

    VB.NETでの実装

    VB.NETでは、同様にCodePagesEncodingProviderを登録することで、Shift-JISをサポートします。

    Imports System.Text
    
    Module Program
        Sub Main()
            ' Shift-JISをサポートするためのエンコーディングプロバイダを登録
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance)
    
            ' Shift-JISエンコーディングを取得
            Dim encoding As Encoding = Encoding.GetEncoding("Shift-JIS")
    
        ' 以下でShift-JISエンコーディングが利用可能です。
        End Sub
    End Module
    

    コードの説明

    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance)

    この一行がポイントです。CodePagesEncodingProvider.InstanceEncoding.RegisterProviderに渡すことで、Shift-JISを含む追加のコードページベースのエンコーディングがサポートされるようになります。このメソッドを呼ばなければ、Shift-JISを使おうとした際に、ArgumentExceptionが発生します。

    Encoding.GetEncoding("Shift-JIS")

    GetEncodingメソッドでShift-JISエンコーディングを取得します。このメソッドはエンコーディングの名前を引数として受け取り、そのエンコーディングを使用するオブジェクトを返します。

    よくある質問 (FAQ)

    1. なぜShift-JISがデフォルトでサポートされていないのですか?

    .NET Coreや.NET 5+では、軽量かつ高速なランタイムを目指しており、一般的でないエンコーディングはデフォルトで省かれています。日本語環境でよく使われるShift-JISもその一部です。

    2. Encoding.GetEncodingで他のエンコーディングも使用できますか?

    はい、CodePagesEncodingProviderを登録すれば、Shift-JIS以外にもEUC-JPやISO-2022-JPなど、さまざまなエンコーディングが使用可能です。

    3. すべての.NETバージョンでこの方法は使えますか?

    この解決方法は、.NET Core 3.0以降および.NET 5+で利用可能です。従来の.NET Frameworkでは、特にエンコーディングプロバイダの登録は不要です。

    まとめ

    .NET Coreや.NET 5+では、Shift-JISエンコーディングを使用するためにCodePagesEncodingProviderの登録が必要です。C#やVB.NETでShift-JISを利用する場合、アプリケーションの初期化時にこのプロバイダを登録することで、スムーズにエンコーディングを使えるようになります。

    Shift-JISエンコーディングの対応に困っている方は、ぜひこの記事の方法を試してみてください。

  • VBのTrueは-1

    VBでTrueを整数型に変換すると「-1」になる理由とは?

    今日、驚いたことがありました。Visual Basic (VB) で True を整数型にキャストすると、その結果が「1」ではなく「-1」になるのです。初めて知ったときは、「なぜ?」と思いました。

    この記事では、この現象の理由について解説します。

    なぜTrueは-1になるのか?

    一般的にプログラミング言語では、True は「1」、False は「0」として扱われることが多いですが、VBは異なる挙動を示します。具体的には、True は「-1」、False は「0」として表現されます。この動作は、VBの設計によるもので、古いコンピュータのアーキテクチャや言語仕様の影響を受けています。

    VBでは、True はビット単位で全てのビットが「1」の状態を指します。整数型で「-1」を2進数に表すと、すべてのビットが「1」となります(符号付き2の補数表現)。一方、False は全てのビットが「0」です。このため、True を整数に変換すると「-1」となるわけです。

    歴史的な背景

    この仕様は、VBがMS-DOSや初期のWindows環境で動作していた時代のレガシーを引き継いでいます。当時の環境では、ブール値をビットマスクとして扱うことが一般的であり、True が全ビット「1」となることで、ビット操作が効率的に行えるという利点がありました。

    参考資料

    詳しくは、Stack Overflowのこちらのスレッドも参考にしてください:
    Why does casting a Boolean to an Integer return -1 for True?

    結論

    VBでのTrue = -1 という挙動は、プログラミング言語の仕様と歴史的な背景によるものです。この特徴を知っておくと、コードを書く際や他の言語と比較する際に、より深い理解が得られるでしょう。

  • VB.NETでURLを既定のブラウザで開く方法

    VB.NETを使用して開発を行う際、アプリケーションから特定のURLを既定のウェブブラウザで開きたい場合があります。例えば、アプリケーション内の「ヘルプ」リンクをクリックした際に、公式ウェブサイトやオンラインマニュアルをブラウザで表示するシナリオが考えられます。本記事では、VB.NETでURLを既定のブラウザで開く方法について解説します。

    1. Process.Startメソッドを使う

    VB.NETでURLを既定のブラウザで開く最も簡単な方法は、Process.Startメソッドを使用することです。このメソッドを使うことで、システムが指定したURLを既定のウェブブラウザで開くことができます。

    以下に、基本的な実装方法を示します。

    Imports System.Diagnostics
    
    Module Module1
        Sub Main()
            Try
                ' URLを既定のウェブブラウザで開く
                Dim psi As New ProcessStartInfo With {
                    .FileName = "http://example.com",
                    .UseShellExecute = True
                }
                Process.Start(psi)
            Catch ex As System.ComponentModel.Win32Exception
                Console.WriteLine($"エラーが発生しました: {ex.Message}")
            End Try
        End Sub
    End Module
    コードの解説:
    • ProcessStartInfoクラス: ProcessStartInfoクラスは、プロセスの起動時に使用する設定を保持します。FileNameプロパティにURLを指定し、UseShellExecuteプロパティをTrueに設定することで、システムがURLをブラウザで開くようにします。
    • 例外処理: Process.Startメソッドは、Win32Exceptionをスローする可能性があるため、Try...Catchブロックを使用して例外を適切に処理します。

    2. なぜ UseShellExecute = True が必要か?

    UseShellExecuteプロパティをTrueに設定することで、システムのシェル機能が使用され、指定したURLが適切にブラウザで開かれます。もしこれをFalseに設定した場合、システムはURLをファイルパスとして解釈しようとするため、URLを開くことができません。

    3. 実際の使用例

    例えば、アプリケーションの「ヘルプ」ボタンをクリックした際に、公式ドキュメントをウェブで表示したいとします。以下のように実装できます。

    Private Sub HelpButton_Click(sender As Object, e As EventArgs) Handles HelpButton.Click
        Try
            Dim psi As New ProcessStartInfo With {
                .FileName = "http://yourwebsite.com/help",
                .UseShellExecute = True
            }
            Process.Start(psi)
        Catch ex As System.ComponentModel.Win32Exception
            MessageBox.Show($"ヘルプページを開けませんでした: {ex.Message}", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    4. まとめ

    VB.NETでURLを既定のブラウザで開くのは非常に簡単で、Process.Startメソッドを使用するだけで実現できます。UseShellExecuteプロパティをTrueに設定することで、URLが正しく解釈され、ユーザーの既定のブラウザで開かれるようになります。例外処理も忘れずに行うことで、ユーザーにより良いエクスペリエンスを提供できるでしょう。

    この方法を使用して、アプリケーションから簡単にウェブリンクを開く機能を追加してみてください。