「.NET固有の機能」の編集履歴(バックアップ)一覧に戻る

.NET固有の機能 - (2007/07/06 (金) 20:14:50) の編集履歴(バックアップ)


.NET Framework固有のTipsです。


アプリケーションの設定値


アプリケーション/ユーザごとの設定を簡単に扱える。
マイクロソフト情報(C# で設定を使用する)

要約

  • ugingに、「System.Configuration」を追加
using System.Configuration;
  • プロジェクトの設定(ソリューションエクスプローラで、プロジェクトを右クリック→プロパティ→設定タブクリック)で、設定値のプロパティを作成する。この時に既定値も指定できる。
  • データの取得は、Properties.Settings.Default.プロパティ名
string s = Properties.Settings.Default.test1;
  • データの保存は、
Properties.Settings.Default.test1 = "hoge";
Properties.Settings.Default.Save();
※Saveメソッドを実行しないと保存されない。
  • 設定ファイルの位置は、「Documents and Settings\<ユーザ名>\Local Settings\Application Data\<会社名>\<アセンブリ名_ハッシュ値>\<アセンブリバージョン>\user.config」となるが、会社名を指定しなかった場合は、アセンブリ名が使われる。


DBアクセス


様々なデータベースに対し、統一的に処理を行うために、冗長な手順を踏む必要がある。そのため、どうしても、とっつきにくい構造になってしまっている。
ただし、JDBCも同じような構造のプログラムになっているので、一つ覚えてしまえば、つぶしがが効くとも言える。
接続情報などは、コードに直接記述するのではなく、アプリケーションの設定値を利用するのが望ましい。
小規模なデータで、リレーションを行わないような場合は、DBを使うよりも、XMLを使用して、XPathで検索したほうが手軽な気がする。

使用するクラス

  • DbProviderFactories
システムに登録されているDbProviderFactoryインスタンスを管理しているクラス
  • DbProviderFactory
プロバイダ情報を格納し、下記クラスのインスタンスを作成するためのクラス
  • DbConnection
データベースへの接続状態を表すクラス
DbProviderFactoryから取得する
JDBCのjava.sql.Connectionに相当する
  • DbCommand
DBに対して実行する命令(SQL文など)を表すクラス
DbProviderFactoryから取得する
JDBCのjava.sql.PreparedStatementに相当する
  • DbDataReader
DBに対する問い合わせ結果を表すクラス
DbCommand.ExceuteQueryから取得する
JDBCのjava.sql.ResultSetに相当する
  • DbDataAdapter
DBに対する命令、接続、結果データの格納を表すクラス
DbCommandとDataSetの橋渡し役
  • DataSet
DBの問い合わせ結果などデータを格納するクラス(データはDbDataAdapterから得られる)
問い合わせ処理に問題が無ければ、1つ以上のDataTableクラスオブジェクトを持つ事になる
なお、問い合わせ結果が1万行あれば、1万行分のデータをメモリに展開する
  • DataTable
一つのテーブルに対するデータを格納するクラス
  • DataColumn
列情報を格納するクラス
  • DataColumnCollection
テーブル内の全ての列情報を格納するクラス
DataColumnのコレクション
  • DataRow
行情報を格納するクラス
  • DataRowCollection
テーブル内の全ての行情報を格納するクラス
DataRowのコレクション


流れ(問い合わせの場合)

// DbProviderFactoryのインスタンスを作成
DbProviderFactory dbProvider = DbProviderFactories.GetFactory("System.Data.OleDb");

// DbProviderFactoryのインスタンスからDbConnectionを取得
DbConnection dbCon = dbProvider.CreateConnection();

// DbConnectionに、ConnectionStringを設定し、Openする
// DBファイルはtest.mdb(Microsoft Access MDB)
dbCon.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data source=test.mdb";
dbCon.Open();
// この時点で、DBとの接続が完了

// DbProviderFactoryのインスタンスからDbCommandを取得
DbCommand dbCmd = dbProvider.CreateCommand();

// DbCommandに、接続情報(DbConnection)をセット
dbCmd.Connection = dbCon;

// DbCommandに、問い合わせ文をセット(サンプルなので適当なselect文)
dbCmd.CommandText = "select * from foo";

// DbDataAdapterを取得
DbDataAdapter dbAdap = dbProvider.CreateDataAdapter();

// DbDataAdapterに、DbCommandを結びつける
dbAdap.SelectCommand = dbCmd;

// 問い合わせ結果を受け取るための、DataSetクラスのインスタンスを作成する
DataSet ds = new DataSet();

// 問い合わせ結果を取得する
dbAdap.Fill(ds);

// DataSetは複数のテーブルに対するデータが保存できるので、
// 1つ以上のテーブルデータが保存されているか確認する
if (ds.Tables.Count > 0)
{
    // 最初のテーブル情報を利用する
    DataTable dt = ds.Tables[0];

    // 問い合わせ結果が1行以上存在するか確認する
    DataRowCollection rows = dt.Rows;
    if (rows.Count > 0)
    {
        // 問い合わせ結果の最初の行の、最初の列の値を出力する
        System.Console.WriteLine(rows[0][0]);
        // 問い合わせ結果の最初の行の、列名が「FIELD1」の列の値を出力する
        System.Console.WriteLine(rows[0]["FIELD1"]);
    }
}

// 接続を切断する
dbCon.Close();

ということらしい…


XML


従来からInternet Explorerの一部として配布されていたMSXMLがあったが、.NET FrameworkのXMLクラスは、様々な点で使い勝手が良くなっている。

  • C言語から使用する場合、文字列をBSTRなどの形にしないといけなかったが、C#言語の場合は、メモリ管理は自動だし、始めからUnicode対応なので、そのまま扱える
  • 何も指定しなくても、改行やインデントされた状態でファイルへ出力できる
  • ほぼCOMインターフェース直接アクセスに近いMSXMLと違い、自動でメモリ管理をしてくれるので、Nodeの参照カウンタ管理などを気にせずに使える
など

ところで、.NET FrameworkのXMLクラスは、ファイルの先頭がXML宣言(<?xml…)でないとエラーになるらしい。コメントであっても。
MS-XMLでは問題なかったのだが…。

また、二つのXMLオブジェクトの結合を行う場合、自身の子ノードでないノードをAppendChildなどで追加させる事になるのだが、自分がCreateしたノード以外のノードを追加する事が出来ないので、ImportNodeメソッドでコピーを作成した後にノードを追加する。
XmlDocument doc1 = new XmlDocument();
XmlDocument doc2 = new XmlDocument();

doc1.Load("test1.xml");
doc2.Load("test2.xml");

XmlNodeList lst = doc1.SelectNodes("/foo/*");
XmlNode parent = doc2.SelectSingleNode("/foo");

foreach (XmlNode node in lst)
{
    parent.AppendChild(doc2.ImportNode(node, true));
}


ファイル名検索

System.IO.DirectoryクラスのGetFilesメソッドを使うとファイル名を手軽に指定したディレクトリ下のファイルをフルパスで文字列配列として取得できる。
string[] sFiles = Directory.GetFiles(@"c:\temp");
とすると、c:\tempディレクトリ下のファイル名を取得できる。

string[] sFiles = Directory.GetFiles(@"c:\temp", "*.txt");
とすると、c:\tempディレクトリ下の、拡張子がtxtのファイル名を取得できる。

ただし、上記の方法では、サブディレクトリ下を検索していない。
そこで、サブディレクトリも検索対象とする場合は、SearchOptionを指定し、
string[] sFiles = Directory.GetFiles(@"c:\temp", "*.txt", SearchOption.AllDirectories);
とする事で、c:\temp以下の全てのディレクトリ下にある、拡張子がtxtのファイルを取得できる。

なお、無効なディレクトリを指定した場合は、例外が発生する。


ファイルやディレクトリの存在確認

System.IO.FileクラスのExistsメソッドを使うとファイルの存在確認が手軽に実現できる。
if (File.Exists(@"c:\temp\foo.txt"))
{
    // ファイルが存在する
}

また、System.IO.DirectoryクラスのExistsメソッドを使えば、ディレクトリの存在確認を行える。


Drag & Drop

Drag & Dropを実現するためには
  • フォームのAllowDropプロパティをtrueにする
  • Drag & Dropの準備を行うDragEnterイベントを作成する
  • Drag & Dropされたファイル名などを受け取るDragDropイベントを作成する
を行う必要がある。

Drag & Dropで複数のファイルを受け取る処理の場合、
private void Form1_DragEnter(object sender, DragEventArgs e)
{
    // ファイルをDrag & Dropの処理対象にする場合
    if (e.Data.GetDataPresent(DataFormats.FileDrop))
        e.Effect = DragDropEffects.All;
}

private void Form1_DragDrop(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(DataFormats.FileDrop))
    {
        string[] sFiles = (string[])e.Data.GetData(DataFormats.FileDrop);
        Array.Sort(sFiles);  // ファイル名を並べ替えたいときには必要
        foreach (string sFileName in sFiles)
            Console.WriteLine(sFileName);
    }
}
の様になる。