VB.NETとC#は似ているか?

同じようなものとは言われたけれど……

私は主にVisualStudioのVisualBasicでアプリ開発をする技術者ですが、プロジェクトによってはちょっと「?」なアサイン(割り当て)をされる事があります。
その一例では、VisualBasicで工場生産管理アプリを作成するという名目で参画した現場で、なぜか工場現場の管理者が持つタブレット端末のアプリ開発にアサインされた事です。

開発主任曰く、

「VBできるんでしょ? タブレットはXamarin(ザマリン)だから、同じようなものだよ。だいじょーぶ、だいじょーぶ」

今になると「??」な言い分ですが、仕方ないので少々苦戦しつつ、タブレットアプリの開発業務をしたことがあります。

C#の引き合いが来たので、思い出したエビソードですが、丁度良いので記事にしてみようと思います。

似ている部分

C#のForm画面/右:VB.NETのForm画面

画面左がC#の起動画面。右がVisualBasicの起動画面です。ほぼ見分けが付かないくらい、そっくりではありますね

プログラムの事始めは、HelloWorldを表示するものなので、早速、両方で比べてみましょう。

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.label1.Text = "HELLO C# WORLD";
        }
    }
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Label1.Text = "HELLO VB WORLD"
    End Sub

左:C#のコード/右:VB.NETのコード

見た目は似ていましたが、同じ結果を得るためのコードを記述すると、少し内容が違います。

VBでは自身のフォームはMeですが、C#ではthisと記述するようです。
また、Sub と End Sub のペアで記述するVBに対して、C#は{}で囲むなどコードの記述方法はけっこう異なっていますね。

C#のコード実行結果/右:VB.NETのコード実行結果

VBとC#のデータベース接続の違いとは?

VB(VisualBasic)での業務アプリ開発では、DB(データベース)との接続は必須です。

今までDBと繋がない業務アプリに出会ったことはありません。なので、C#での開発もDBに繋がないと話にならないと思います。

DBにはいろいろなものがありますが、VBで各種DBに繋いだサンプルは、こちらの過去記事をご覧下さい。

C#でもDB接続を試すため、VBのサンプルコードを移植してみましょう。

サンプルデータベース

DBは、一番設置が簡単なubuntu上のmariaDBにしました。

サンプルデータは気象庁から、最高気温と最低気温のデータをCSVで取り寄せ、観測場所、日付、最高気温、最低気温のデータベースを作ります。

VBと同じく、データベース接続を部品にする

今回の環境では、データベースは同じLAN上にあり、C#のプログラムから直接SQLを投げる形式をとってみます。

この場合、流れとしては

  • DBに接続
  • SQLを送信
  • 結果を受領
  • DBとの接続を解除

という流れになります。

VBで作ったときは、モジュールを設置して、これらを部品化していました。

C#のプロジェクト画面で追加を見ても、モジュールは存在しません。

C#の場合、モジュールではなく、クラスとしてこれを部品化するそうです。

クラスを選択し、名称を入れます。

今回は、DatabaseHelperとしました。

クラスが追加されました。

当然ですが、現在は空っぽです。

VBのとき使用したMySql.Dataは、C#でも使用できるとの事なので、Ngetからインストールします。

VBとC#のコーディングの違い

移植作業をしながら気がついたのですが、VBだとコマンドの先頭は大文字に変換される事が多いですが、C#だとエラーになります。
しばらく悩んでしまいました。

C#では大文字小文字が区別されるとの事です。

また、VBでは必要ないですが、C#では行の最後は;(セミコロン)が必要です。

この他にも比較すると

public static MySqlConnection mysqlCon = new MySqlConnection();
public static MySqlCommand sqlCommand = new MySqlCommand();
Public mysqlCon As New MySqlConnection
Public sqlCommand As New MySqlCommand

左:C#のコード/右:VB.NETのコード

MySql.DataのMySqlConnectionのインスタンスを作成するコードですが、VBでは「Dim 変数名 As New 型名」で型と同時にインスタンス化できますが、C#では「型名 変数名 = new 型名();」という形式で書く必要があります。

//データ取得のためのアダプタの設定
MySqlDataAdapter adapter = new MySqlDataAdapter(query, mysqlCon);

//データを取得
adapter.Fill(dt);
' データ取得のためのアダプタの設定
Dim Adapter = New MySqlDataAdapter(query, mysqlCon)

' データを取得
Adapter.Fill(dt)

左:C#のコード/右:VB.NETのコード

こちらもSQLを実際に実行する部分ですが、VBだとDimで「この後は変数の名前だ」と宣言しますが、C#の場合、宣言は不要で[型] [変数名]です。

また、VBではコメントが ’コメント でしたがC#では //コメント 名前空間の読み込みが、VBではImports ですが、C#ではusingなど細かい違いがありますが、移植は可能でした。

出来上がったDatabaseHelperクラス

出来上がったコードはこのようになります。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql.Data.MySqlClient;

namespace C_HELLO
{
    class DatabaseHelper
    {
        public static MySqlConnection mysqlCon = new MySqlConnection();
        public static MySqlCommand sqlCommand = new MySqlCommand();
        //データベース接続
        public static void sql_st()
        {
            var builder = new MySqlConnectionStringBuilder
            {
                Server = "192.168.1.29",
                SslMode = MySqlSslMode.Disabled,
                Port = 3306,
                UserID = "c_test",
                Password = "password",
                Database = "meteorological"
            };

            mysqlCon.ConnectionString = builder.ToString();
            mysqlCon.Open();

        }
        //データベース切断
        public static void sql_cl()
        {
            mysqlCon.Close();
        }

        //データセットを返すSQLを処理する
        public static DataTable sql_result_return(string query)
        {
            var dt = new DataTable();
            try
            {
                //データ取得のためのアダプタの設定
                MySqlDataAdapter adapter = new MySqlDataAdapter(query, mysqlCon);

                //データを取得
                adapter.Fill(dt);

            }
            catch
            {
            }
            return dt;

        }

    }
}

フォームから呼び出す処理を追加

フォームはForm1が既に在りますから、サイズを変更し、private void Form1_Load(object sender, EventArgs e)の内容を書き換えます。

  • DBに接続
  • 最高気温が一番大きなレコード抽出
  • フォーム部品に配置
  • DB切断

出来上がったコードはこのようになります。

private void Form1_Load(object sender, EventArgs e)
        {
            DatabaseHelper.sql_st();

            string sql1 = "SELECT";
            sql1 += "`Place`";
            sql1 += ",`Observation`";
            sql1 += ",`maximum`";
            sql1 += " FROM `temperature`";
            sql1 += " WHERE maximum = ";
            sql1 += "(";
            sql1 += "   SELECT";
            sql1 += "    MAX(maximum)";
            sql1 += "   FROM temperature";
            sql1 += ")";
            sql1 += ";";

            DataTable dTb1 = DatabaseHelper.sql_result_return(sql1);

            if (dTb1.Rows.Count == 0)
                {
                    this.Text = "失敗";
                    this.label1.Text = "接続できませんでした";
                }
                else
            {
                foreach (DataRow drow in dTb1.Rows)
                {
                    this.Text = "最高気温";
                    this.label1.Text = drow[0].ToString();
                    this.label2.Text = drow[1].ToString();
                    this.label3.Text = drow[2].ToString() + "℃";

                }
            }

            DatabaseHelper.sql_cl();

        }

動作確認

実行すると、無事にクラスを呼び出し、DBに接続して最高気温の場所、日時、温度を表示しました。

C#としては、DataTableを直接参照はしないのが一般的

さて、動作はしたので一安心ですが、C#でのデータベース接続の際、結果の受取はDTO(Data Transfer Object)を使うのが一般的なようです。

VBでも大きなプロジェクトのコードになるとよく使われていました。
そちらが「作法」というものでしたら、今回の試作プログラムもそれにあわせてみましょう。

修正したDatabaseHelperクラス

出来上がったコードはこのようになります。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql.Data.MySqlClient;

namespace C_HELLO
{

    public class TemperatureDto
    {
        public string Place { get; set; }
        public DateTime Observation { get; set; }
        public double Maximum { get; set; }
        public double Lowest { get; set; }
    }

    class DatabaseHelper
    {
        public static MySqlConnection mysqlCon = new MySqlConnection();
        public static MySqlCommand sqlCommand = new MySqlCommand();

        //データベース接続
        public static void sql_st()
        {
            var builder = new MySqlConnectionStringBuilder
            {
                Server = "192.168.1.29",
                SslMode = MySqlSslMode.Disabled,
                Port = 3306,
                UserID = "c_test",
                Password = "password",
                Database = "meteorological"
            };

            mysqlCon.ConnectionString = builder.ToString();
            mysqlCon.Open();

        }
        //データベース切断
        public static void sql_cl()
        {
            mysqlCon.Close();
        }

        //データセットを返すSQLを処理する
        public static List<TemperatureDto> sql_result_return(string query)
        {
            DataTable dt = new DataTable();

            //データ取得のためのアダプタの設定
            MySqlDataAdapter adapter = new MySqlDataAdapter(query, mysqlCon);

            //データを取得
            adapter.Fill(dt);

            // 2. DataTable → DTOリスト変換
            List<TemperatureDto> list = new List<TemperatureDto>();

            foreach (DataRow row in dt.Rows)
            {
                list.Add(new TemperatureDto
                {
                    Place = row["Place"].ToString(),
                    Observation = Convert.ToDateTime(row["Observation"]),
                    Maximum = Convert.ToDouble(row["Maximum"]),
                    Lowest = Convert.ToDouble(row["Lowest"])
                });
            }
            return list;
        }

    }
}

修正したForm1_Load

出来上がったコードはこのようになります。

private void Form1_Load(object sender, EventArgs e)
        {
            DatabaseHelper.sql_st();

            string sql1 = "SELECT";
            sql1 += "`Place`";
            sql1 += ",`Observation`";
            sql1 += ",`Maximum`";
            sql1 += ",`Lowest`";
            sql1 += " FROM `temperature`";
            sql1 += " WHERE maximum = ";
            sql1 += "(";
            sql1 += "   SELECT";
            sql1 += "    MAX(maximum)";
            sql1 += "   FROM temperature";
            sql1 += ")";
            sql1 += ";";

            List<TemperatureDto> list = DatabaseHelper.sql_result_return(sql1);

            if (list.Count == 0)
                {
                    this.Text = "失敗";
                    this.label1.Text = "接続できませんでした";
                }
                else
            {
                var dto = list[0];

                    this.Text = "最高気温";
                    this.label1.Text = dto.Place;
                    this.label2.Text = dto.Observation.ToShortDateString();
                    this.label3.Text = dto.Maximum.ToString("F1") + "℃";
            }

            DatabaseHelper.sql_cl();

DatabaseHelper.sql_result_return(sql1);を格納する部分をDataTableから、listに変更。

このlistは、DatabaseHelperに追加したTemperatureDtoを参照しています。

動作確認

DTO型だとIEEE754の精度誤差が表示されるため、37.4が37.400001525878906として格納されます。

このため、表示を小数点1までにしてあります。

まとめ

VBとC#を簡単に比較してみました。

同じVisualStudioに属するだけに、開発インターフェイスの見た目は確かに似ているのですが、コードの書き方や考え方には、けっこう大きな違いがあります。

VB(VisualBasic)は「BASIC(初心者向け汎用記号命令コード)」の系譜を継いでおり、ある程度ゆるくても動く設計になっています。

一方、C#はC言語やC++と同じく、UNIX環境で発展してきたプログラミング文化の影響を受けており、型安全性が高く、厳密な記述が求められるため、明示的な型宣言や構文の正確さを要求されます。

ただ、この明示的な型宣言や構文の正確さを身につけておけば、VBのプログラミングにも役立つかと思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です