using文の使い方について

このQ&Aのポイント
  • visual C# 2010 Expressを使用している場合、データベースのコネクションを取得するメソッドを作成することができます。
  • 生成したMySqlConnectionは適切に開放されているため、メモリリークの心配はありません。
  • 上記のコードは、データベースから値を取得するシンプルな例です。
回答を見る
  • ベストアンサー

using文の使い方について

visual C# 2010 Express を使用しています。 MySqlConnectionのデータベースのコネクション部分だけを次のようなメソッドとして、 そのオブジェクトだけを得たいと思いまして、次のような感じにしたのですが、 class Program { static void Main(string[] args) { MySqlConnection conn = GetConnection(); using (MySqlCommand cmd = new MySqlCommand("SELECT * FROM tbl where id = '1'", conn)) { conn.Open(); MySqlDataReader reader = null; reader = cmd.ExecuteReader(); reader.Read(); int i = reader.GetInt32(reader.GetOrdinal("id")); Console.WriteLine(i.ToString()); Console.ReadLine(); conn.Close(); } } static MySqlConnection GetConnection() { string connStr = "server=localhost;Database=test;Uid=root;Pwd="; using (MySqlConnection conn = new MySql.Data.MySqlClient.MySqlConnection(connStr)) { return conn; } } } 一応これで表示できたのですが、 これで生成したMySqlConnectionはちゃんと開放(消滅)されているのでしょうか? このようなやり方でデータを取得しているのを見たことがないで 大丈夫なのかな?と思いました。。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

IDisposable.Disposeは,大元はUnmanaged Resource, つまりは.NET Frameworkが管理しないリソース, ぶっちゃければメモリ以外のリソースの統一した解放手段を提供するための物です。 で,IDisposable自体は自分できっちり実装する必要があります。 class Class1 : IDisposable { private bool _disposed = false; private int _i = 2; ~class1 () { Dispose(false); } public int { get { if (_disposed) throw new ObjectDisposedException(); // 破棄されたオブジェクト return _i; } set { if (_disposed) throw new ObjectDisposedExecption(); _i = value; } } protected virtual void Dispose (bool disposing) { if (_disposed) return; // 多重Disposeしても安全であること if (disposing) { // フィールドにあるIDisposableの解放等 } _disposed = true; } public void Dispose () { Dispose(true); GC.SuppressFinalize(this); // ファイナライザの呼び出しを抑制する } } で,本題ですが,トランザクションとかが関係しないのであれば, Queryメソッドでコネクションを開き,DataSetなりにデータを読んで,コネクションを閉じるまでしてしまいます。 IDisposableなオブジェクトは,他のオブジェクト以上に所有権を考えないといけないため, できるだけIDisposableなオブジェクトはusingで囲っておきたいです。 ASP.NETだとまた別の解があって, HttpContext.Current.ApplicationInstance.EndRequestイベントで解放するように構築してしまう,というのも手です。 ASP.NETだと短い時間で処理が終わるので,終了イベントを捕まえてそこで解放しても十分,という判断です。 # 実際にこういう作りにしたことがあります。

takagoo100
質問者

お礼

ご回答ありがとうございます。 なるほど、自分のやり方ではちゃんと実装してなかったわけですね・・・ 参考になりました。 やはりそうですか、usingで囲うしかないですかね。。 というより、考え方を変えて設計する必要がありそうですね。 これからも自分なりに作っていきたいと思います。

その他の回答 (1)

回答No.1

個人的には,「えっ,これで動くの?」という感じですが……。 using文は,そのブロックから出たタイミングでオブジェクトをDisposeします。 このため,GetConnectionメソッドの戻り値は「破棄されたオブジェクト」になり, 本来はOpenメソッドがObjectDisposedExceptionを発生させなければなりません。 書き換えるなら,こうでしょうか。 class Program { static void Main(string[] args) { using (MySqlConnection conn = GetConnection()) using (MySqlCommand cmd = new MySqlCommand("SELECT * FROM tbl where id = '1'", conn)) { conn.Open(); using (reader = cmd.ExecuteReader()) // IDataReaderはIDisposableなのでDisposeを呼ぶ必要がある { reader.Read(); int i = reader.GetInt32(reader.GetOrdinal("id")); Console.WriteLine(i.ToString()); } // ここでreaderが解放される conn.Close(); // 書いた方が行儀が良いが,省略可能 } // ここでcmdとconnが解放される Console.ReadLine(); } static MySqlConnection GetConnection() { const string connStr = "server=localhost;Database=test;Uid=root;Pwd="; // constを付けておくと,変更不可能になる return new MySql.Data.MySqlClient.MySqlConnection(connStr); } }

takagoo100
質問者

お礼

ご回答ありがとうございます。 これは今も試しましたが確かに取得できるのです。。 自分的にはもちろんなぜだかは分からないのですが、 最初はシンプルなIDisposableを継承した class class1 : IDisposable { public int i = 2; public void Dispose() { Console.WriteLine("Dispose"); Console.ReadLine(); } } でGetConnection()のような使い方を試してみたのですが、これも値が変化しました。 もしお手数でなければ、Yune-Kichiさんの環境でも試してみて頂けないでしょうか? そして、提示して頂いたコードですが なるほど、たしかにこのやり方ならMySqlConnectionを GetConnectionに収めることができますね。 そもそもなんでこんなことを考えたかというと、 これも先ほどのPHPのフレームワークじゃないですけど 例えばzend frameworkのZend_Dbというクラスを使えば http://framework.zend.com/manual/ja/zend.db.adapter.html $db = Zend_Db::factory('Pdo_Mysql', $params); $db->query(); 一度$dbを作ってしまえば、あとはそれを使ってシンプル(?)な 記述で便利というか、でもそれは言語の固有の特性で 解放を自動的に行ってくれるので、このようなやり方が可能なのだと思います。 C#では当然ながら自動的に解放しないのでusingの中で処理を記述せざるえないわけですよね? 自分的にはなんとかzend frameworkじゃないですけど、それに近いクラスを C#でも作りたい(というか慣れ親しんだイメージのまま利用したい)と思ってて、 でも言語的にさっきのオブジェクトの解放もそうですけど、 クラスやメソッドの構成に影響を与える違いもでてくるので、どうしようか悩んでいるとろこです(う~ん、うまく説明できず申し訳ないです・・・) ちょっと漠然としすぎる質問で申し訳ないですが、もしYune-KichiさんがC#でデータベース関連のライブラリを 作成というかラップするようなクラスを作るとしたらどのように作りますか?先ほどの解放の問題も含めてですが

関連するQ&A

  • C#のusing文でメソッドの戻り値にオブジェクト

    C#4.0を使用しています。 例えば、次のようなメンバやメソッドの戻り値がオブジェクトを返す場合に、 usingの()の中で記述した時に確実にリソースを解放してくれるのでしょうか? そもそもこのような使い方(メソッドがオブジェクトを返す)をして良いのでしょうか? public class SQLiteAdapter {  public DbConnection Connection  {   get { return new SQLiteConnection("Data Source=test.db"); }  } } adapter = new SQLiteAdapter(); using (DbConnection conn = adapter.Connection) { } なぜこのようなことをやりたいと思ったかというと、 SQLiteやMySqlの共通のラッパークラスのようなものを作りたいと思いました。 ただほとんどの処理の構造は同じなので、 違う部分だけをメソッドの戻り値で済ましたいと思いました。 例えばDbConnectionの場合、 SQLiteならSQLiteConnection MySqlならMySqlConnection 例えばクエリを実行する処理では public Boolean ExecuteNonQuery(string sql) { SQLiteTransaction tx = null; using (SQLiteConnection conn = new SQLiteConnection(this.connectionString)) using (SQLiteCommand cmd = conn.CreateCommand()) { try { conn.Open(); //トランザクション開始 tx = conn.BeginTransaction(); cmd.CommandText = sql; cmd.Transaction = tx; //SQL実行 cmd.ExecuteNonQuery(); //コミット tx.Commit(); return true; } catch (Exception ex) { //ロールバック if (tx != null) tx.Rollback(); return false; } finally { } } } SQLiteTransaction、SQLiteCommand、SQLiteConnection の3箇所をMySqlなら MySqlTransaction、MySqlCommand、MySqlConnection に変更すればいいわけですよね? なのでそれぞれのアダプター側でこのように同じような処理を書かずに 基本クラス側で処理を記述し、各派生クラス側ではリソース(オブジェクト)を返すメソッド を用意すればいいのかな?と思いました。 ただ質問のようなusing文の使い方で大丈夫なのか疑問に思って質問しました。 よろしくお願いします。

  • DBから取得した値の変換方法

    DB MySQL カラム:name varchar(255),ucs2_bin データ:てすと 上記のデータを下記の処理で(VB.Net)取得しようと すると文字が化け(????)て取得されてしまうのですが デコードの仕方が良く分かりません。 System.Text.~を使うと思うのですが何を指定したら いいのか分からないのでご教授お願い致します。 ちなみに言語は日・中・英と対応する必要があります。 --処理-- Dim conn As New MySQLConnection( _ String.Format("Port={0};Server={1};Data Source={2};User ID={3};Password={4}", _ port, computer, database, user, password)) Dim cmd As MySQLCommand Dim red As MySQLDataReader conn.Open() Dim sql = "select name from test" cmd = New MySQLCommand(sql, conn) red = CType(cmd.ExecuteReader(), MySQLDataReader) Do While red.Read Console.WriteLine(red("NAME")) Loop red.Close() cmd.Dispose()

  • Mysqlへの接続に関して

    MysqlへVisual Studio 2008 のC#で接続しようとしています。 接続方法としては、クライアントから"mysql-connector-net-6.1.5"をインストールして ODBCを使わずに接続しようとしています。 参照設定で、"MySql.data"を指定し、以下のように記述しましたが、どうしても下記の ようなエラーが出力されてしまいます。 原因がわかりましたら教えて頂きたいと思います。 《記述内容》 using MySql.Data.MySqlClient; string sqlcmd = "userid=root;" + "password=000000;" + "database=db_name;" + "Host=999.999.999.999"; string cmdstr, cmdcnt; cmdstr = "select * from t_user ;"; MySqlDataReader reader = null; MySqlConnection conn = new MySqlConnection(sqlcmd); //MySQLコマンド MySqlCommand selcmd = new MySqlCommand(cmdstr, conn); //MySQL接続 conn.Open(); この conn.Open(); のところで下記のエラーが出てしまう。 //エラー内容 Unable to connect to any of the specified MySQL hosts. よろしくお願いします。

    • ベストアンサー
    • MySQL
  • C#でのSQLへのアクセスについて

    SQL Serverのテーブルをコンソール上に表示する為のコードを書いたのですが SqlConnection SqlCommand SqlDataReader に対してエラーが出しまい、修正方法が分からず、どなたか教えて頂けないでしょうか? 【ソースコード】 using System; using System.Configuration; using System.Data; using System.Data.SqlClient; using Microsoft.Data.SqlClient; static void Main(string[] args) { string connectionString = "Data Source=○○;Initial Catalog=○○;User ID=○○;Password=○○;"; using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); using (SqlCommand command = new SqlCommand("SELECT * FROM [○○]", connection)) using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { Console.WriteLine(reader["column1"]); Console.WriteLine(reader["column2"]); } } } }

  • 他クライアントからの接続に関して

    教えて下さい。 C#で作成したプログラムを自分の開発環境以外のクライアントで実行したところ、 エラーでMySqlへ接続ができませんでした。 自身の開発環境では、アクセスできますが、そのEXEファイルを他クライアント から実行するとエラーとなってしまいます。 各クライアントへは、自開発環境と同じく、"mysql-connector-net-6.1.5"をインストール してあります。 ちなみにソース上の記述は以下のようになっています。 《記述内容》 using MySql.Data.MySqlClient; string sqlcmd = "userid=root;" + "password=000000;" + "database=db_name;" + "Host=999.999.999.999"; string cmdstr; cmdstr = "select * from t_user ;"; MySqlDataReader reader = null; MySqlConnection conn = new MySqlConnection(sqlcmd); //MySQLコマンド MySqlCommand selcmd = new MySqlCommand(cmdstr, conn); エラーの内容は、   "アプリケーションのコンポーネントで、ハンドルされていない例外が発生しました。[続行」   をクリックすると、アプリケーションはこのエラーを無視し、続行しようとします。[終了]   をクリックすると、アプリケーションは直ちに終了します。   ファイルまたはアセンブリ'MySql.data,Version=5.0.9.0,Culture=neutral,PublicKeyToken =C5687fc88969c44d'、またはその依存関係の1つが読み込めませんでした。 指定されたファイル   が見つかりません。" と表示されます。 原因を教えて頂きたく。。。。 よろしくお願いします。 

    • ベストアンサー
    • MySQL
  • VB.NetによるMySQL接続について

    VB.NET(2012)よりMySQLへの接続についてご教示ください。 現状、下記のようなエラーが発生し、DB接続ができない状況です。 'MySQLConnection' は、名前空間 'MySql.Data.MySqlClient' では不適切です。 'MySQLCommand' は、名前空間 'MySql.Data.MySqlClient' では不適切です。 'MySQLDataReader' は、名前空間 'MySql.Data.MySqlClient' では不適切です。 【ソース】 Imports MySql.Data.MySqlClient Public Class Form1 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim con As MySQLConnection Dim cmd As MySQLCommand Dim dr As MySQLDataReader End Sub End Class 【設定】 Connector/NETのインストール メニューのプロジェクト→参照の追加→拡張よりMySql.Dataを指定 メニューのプロジェクト→DB_Accessのプロパティ→参照よりMysql.Data→プロパティ内のローカルコピー:True 参照よりインポートされた名前空間(I)→Mysql、Mysql.Data・・・その他Mysqlのチェックをオン 【環境】 OS:Windows7 開発:.Net2012 DB・サーバ環境:XAMPP(アパッチ、MySQL) HPでいろいろ調べましたがどれも似たような内容の為、解決できておりません。 何か足りないのでしょうか。 何卒、ご教示のほどよろしくお願い致します。

  • C#からMySQLにデータを書き込んだ時の文字化け

    お世話になります。 C#でMySQLにアクセスしようとしています。 文字列以外はできているのですが、文字列の入力、 取得で文字化けしてしまいます。 対処の方法をご指導いただけますよう、お願いいたします。 下記がコードになります。 string myConnectionString = "Database=test;Data Source=localhost; User Id=root;Password=''"; MySqlConnection myConnection = new MySqlConnection(myConnectionString); string mySelectQuery = "insert into characters values('5','あいうえおかきくけこ','10','3')";                                            ↑この文字列が化ける MySqlCommand myCommand = new MySqlCommand(mySelectQuery, myConnection); myConnection.Open(); MySqlDataReader myReader; myReader = myCommand.ExecuteReader(); myReader.Close(); myConnection.Close(); mySelectQuery = "SELECT * FROM characters"; myCommand = new MySqlCommand(mySelectQuery, myConnection); myConnection.Open(); myReader = myCommand.ExecuteReader(); while (myReader.Read()) { MessageBox.Show(myReader.GetString(0) + ", " + myReader.GetString(1)); } myReader.Close(); myConnection.Close(); なお、MySQLはUTF-8を基準にしています。 以上、よろしくお願いいたします。

  • SQLとC#connectについて

    独学で勉強しているのですがさっぱり分かりません...。 C# visual studio へ SQL server情報を読み込みたいのですが...Button1を押したら、sql に作成してある(ingredientという) データをrichtextbox へ送りたいです。 今のところ、SQLにcommandを送り、開き、リーダーで呼びました。 SqlConnection sc = new SqlConnection(@"........."); SqlCommand cmd; cmd = new SqlCommand ("Select * from ingredients", sc); sc.Open(); SqlDataReader reader = cmd.ExecuteReader(); その後作っておいたクラスでリストを作りストアしました。ingredientにはidとnameだけです。 List<Ingredient> ingredients = new List<Ingredient>(); while (reader.Read()) {  string testID = reader["id"].ToString(); string ingName = reader["name"].ToString(); Ingredient oneIng = new Ingredient(Convert.ToInt32(testID), ingName); ingredients.Add(oneIng);} 今リストの中に情報が入っているということは分ります。でも、これをrichtextboxにどう整理して入れるのかは分りません。教えて下さい!!!

  • C# で発生したException.MessageをMysqlに登録した際に文字化けが発生する

    C# で発生したException.MessageをMysqlに登録した際に文字化けが発生する. すいませんが、皆様のお力をお貸しください。 以下のようなコードでC#で発生した例外の情報をMySQLに登録しようとしていますが、「??????????????」の様に文字化けして日本語が登録できません。 ---- C#のコード public void errorLog(Exception exception){ MySqlConnection mySqlConnection = new MySqlConnection(); mySqlConnection.ConnectionString = "Database=airreserve;Data Source=localhost;User Id=root;Password=root"; mySqlConnection.Open(); MySqlCommand mySqlCommand = mySqlConnection.CreateCommand(); StringBuilder sql = new StringBuilder(); sql.Append(" INSERT INTO system_error_log ("); sql.Append(" error_message, "); sql.Append(" error_detail, "); sql.Append(" update_time "); sql.Append(" ) VALUES ( "); sql.Append(" @message, "); sql.Append(" @error, "); sql.Append(" now() "); sql.Append(" ) "); mySqlCommand.CommandText = sql.ToString(); mySqlCommand.Parameters.AddWithValue("@message", exception.Message); mySqlCommand.Parameters.AddWithValue("@error", exception.StackTrace); mySqlCommand.ExecuteNonQuery(); } ---- MySQLの設定 -------------- mysql Ver 14.12 Distrib 5.0.85, for Win32 (ia32) Connection id: 3 Current database: airreserve Current user: root@localhost SSL: Not in use Using delimiter: ; Server version: 5.0.85-community-nt MySQL Community Edition (GPL) Protocol version: 10 Connection: localhost via TCP/IP Server characterset: utf8 Db characterset: utf8 Client characterset: utf8 Conn. characterset: utf8 TCP port: 3306 Uptime: 8 hours 8 min 34 sec Threads: 5 Questions: 581 Slow queries: 0 Opens: 54 Flush tables: 1 Open tables: 1 Queries per second avg: 0.020 --------------

  • C++/CLI 関数がインポートできない

    Visual C++でビルドすると、 1>ConnectionWrapsTest.cpp(12): warning C4679: 'ConnectionWraps::Class1::GetConnection' : メンバーをインポートできませんでした 1> 型 'ConnectionWraps::Class1 ' をアセンブリ 'ConnectionWraps, Version=1.0.4594.40998, Culture=neutral, PublicKeyToken=null' からインポート中に、この診断が発生しました。 という様なエラーがいくつかでて、失敗してしまいます。 何故この様なエラーが出るのか理解出来ません。解決策を教えてください。 DLL側 ------------------------------------------- // ConnectionWraps.h #pragma once using namespace System; using namespace std; #include <string> namespace ConnectionWraps { public ref class Class1 { // TODO: このクラスの、ユーザーのメソッドをここに追加してください。 public: static int GetConnection(string address, string port, string database, string userid, string password); static void CloseConnection(int handle); static int ChangeDatabase(int handle, string databaseName); static int Command(int handle, string sql); }; } -------------------------------------------------- 実行ファイル側 ---------------------------------------------------- // ConnectionWrapsTest.cpp : メイン プロジェクト ファイルです。 #include "stdafx.h" #include <string> using namespace std; using namespace System; using namespace ConnectionWraps; int main(array<System::String ^> ^args) { Console::WriteLine(Class1::GetConnection("a", "a", "a", "a", "a", "a")); return 0; } -------------------------------------------------

専門家に質問してみよう