GrapeCity ActiveReports for .NET 16.0J
カスタムデータプロバイダ
ActiveReportsユーザーガイド > サンプルとチュートリアル > チュートリアル > ページレポート/RDLレポートのチュートリアル > カスタマイズ > カスタムデータプロバイダ

ページレポート/RDLレポートでは、カスタムデータプロバイダを使用し、実行時と設計時に正規以外のデータソースを使用することができます。このチュートリアルでは、カスタムデータプロバイダを使用したプロジェクトのソリューションを作成し、CSVファイルからデータを取得する方法を紹介します。

このトピックでは、以下のタスクを行います。

このチュートリアルを完了すると、CSVファイルから取得したデータを読み込んだレポートがデザイナ上に表示されます。

カスタムデータプロバイダのためのデザイナプロジェクトを作成する

  1. Visual Studioでは、Windowsフォームプロジェクトを作成し、名前を「CustomDataProviderDemo」に変更します。
  2. Visual Studioのツールボックスの[ActiveReports 16]タブから[ReportExplorer]をドラッグし、デフォルトのWindowsフォーム上にドロップし、フォームのサイズを使いやすい大きさに変更します。
  3. [プロパティ]ウィンドウから、ReportExplorerのDockプロパティをLeftに設定します。
  4. 通常のツールボックスから[RichTextBox]コントロールをフォーム上にドラッグし、Dockプロパティを「Topに設定します。
  5. Textプロパティに以下のテキストを追加します(テキストボックスをドロップダウンし、テキスト全体が追加されたかを確認してください)。
    テキスト(RichTextBoxのTextプロパティに貼り付けます)
    コードのコピー
    1.レポートエクスプローラでは、データソースノードを右クリックし、[データソースの追加]を選択します。
    2.[レポートデータソース]ダイアログでは、全般のページに2つの種類ボックスをドロップダウンし、CSV Data Providerを選択してOKをクリックします。
    3.レポートエクスプローラで、DataSource1を右クリックし、[データセットの追加]を選択します。
    4.表示されるダイアログでは、クエリのページを選択します。
    5.クエリボックスをドロップダウンし、カスタムクエリエディタを表示します。
    6.CSVファイルの選択ボタンをクリックし、このプロジェクトにCategories.csvファイルを開きます。
    7.OKをクリックして設定を保存し、ダイアログを閉じます。
    8.プレビューをクリックし、CSVから取得したデータのレポートを表示します。
    
  6. Visual Studioのツールボックスの[ActiveReports 16]タブから[Designer]コントロールをフォーム上の空いている部分にドラッグします。
  7. DockプロパティをFillに設定し、[Designer]コントロールを右クリックし、「最前面へ移動」を選択します。
  8. [ReportExplorer]コントロールを選択し、[プロパティ]ウィンドウからReportDesignerプロパティをドロップダウンし、Designer1を選択します。
  9. フォームのタイトルバーをダブルクリックし、Form Loadイベントのイベント処理メソッドを作成し、以下のコードを追加します。

    Visual Basic

    Visual Basicコード(クラスの上貼り付けます)
    コードのコピー
    Imports System.Xml
    Imports System.IO
    Imports GrapeCity.ActiveReports.Design
    

    C#

    C#コード(クラスの上貼り付けます)
    コードのコピー
    using System.Xml;
    using System.IO;
    using GrapeCity.ActiveReports.Design;
    
  10. Form Loadイベントに以下のコードを追加します。

    Visual Basic

    Visual Basicコード(Form_Loadイベント内に貼り付けます)
    コードのコピー
    Using reportStream = File.OpenRead("DemoReport.rdlx")
            Using reader = XmlReader.Create(reportStream)
                    Designer1.LoadReport(reader, DesignerReportType.Page)
            End Using
    End Using
    

    C#

    C#コード(Form_Loadイベント内に貼り付けます)
    コードのコピー
    using (var reportStream = File.OpenRead("DemoReport.rdlx"))
     {
         using (var reader = XmlReader.Create(reportStream))
          {
             designer1.LoadReport(reader, DesignerReportType.Page);
          }
     }
    

カスタムデータプロバイダを使用するためのプロジェクトを作成する

  1. ソリューションエクスプローラーから、プロジェクトを右クリックし、[追加]を選択した後、[新しい項目]を選択します。
  2. 表示されるダイアログでは、[テキストファイル]を選択し、ファイル名を[GrapeCity.ActiveReports.config]に変更し、[追加]をクリックします。 
  3. ソリューションエクスプローラーから、GrapeCity.ActiveReports.configを選択し、[プロパティ]ウィンドウから「出力ディレクトリにコピー」常にコピーするに設定します。
  4. 以下のテキストをファイルに貼り付けて保存します('Configuration' 要素が宣言されていません。と言う警告が表示されますが、無視してください)。
    Configファイルに貼り付けます
    コードのコピー
    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration>
      <Extensions>
        <Data>
          <Extension Name="CSV Custom" DisplayName="CSV Data Provider" 
            Type="CustomDataProvider.CSVDataProvider.CsvDataProviderFactory, 
              CustomDataProvider" 
              CommandTextEditorType="CustomDataProvider.CSVDataProvider.QueryEditor, 
            CustomDataProvider"/>
        </Data>
         </Extensions>
    </Configuration>
    
  5. ソリューションエクスプローラーから、プロジェクトを右クリックし、[追加]を選択した後、[新しい項目]を選択します。
  6. 表示されるダイアログでは、[テキストファイル]を選択し、ファイル名を「Categories.csv」に変更し、[追加]をクリックします。 
  7. ソリューションエクスプローラーから、Categories.csvを選択し、[プロパティ]ウィンドウから「出力ディレクトリにコピー」常にコピーするに変更します。
  8. 以下のテキストをファイルに貼り付けて保存します。
    テキストファイルに貼り付けます
    コードのコピー
    EmployeeID(int32),LastName,FirstName,Role,City
    1,James,Yolanda,Owner,Columbus
    7,Reed,Marvin,Manager,Newton
    9,Figg,Murray,Cashier,Columbus
    12,Snead,Lance,Store Keeper,Columbus
    15,Halm,Jeffry,Store Keeper,Columbus
    17,Hames,Alma,Store Keeper,Oak Bay
    18,Nicki,Aubrey,Store Keeper,Columbus
    24,Cliett,Vikki,Store Keeper,Newton
    

データを表示するためのレポートを追加する

  1. ソリューションエクスプローラーから、プロジェクトを右クリックし、[追加]を選択した後、[新しい項目]を選択します。
  2. 表示されるダイアログでは、[ActiveReports 16.0J RDL レポート]を選択し、ファイル名を「DemoReport」に変更し、[追加]をクリックします。 (RDLレポートでは、すべてのデータは1ページに表示されます。)
  3. ソリューションエクスプローラーから、DemoReportを選択し、[プロパティ]ウィンドウから「出力ディレクトリにコピー」常にコピーするに設定します。
  4. ActiveReports 16のRDLレポートのツールボックスから[Table]データ領域をレポートにドラッグします。
    メモ: ページレポートを使用する場合には、1つのページにすべてのデータを表示するためにFixedSizeプロパティを設定する必要があります。
  5. [Table]をクリックし、左端に行ハンドルを表示します。フッタ行の左端にある行ハンドルを右クリックし、[行の削除]を選択し、[Table]からフッタ行を削除します。
  6. レポートエクスプローラでは、各テキストボックスを選択し、以下のようにプロパティを設定します。(レポートエクスプローラが表示されていない場合は、[表示]メニューから、[その他のウインドウ]を選択し、[ActiveReports 16.0Jレポートエクスプローラ]を選択します。) 
    テキストボックス名 背景色
    TextBox1 名前 MediumSlateBlue
    TextBox2 地位 MediumSlateBlue
    TextBox3 都市 MediumSlateBlue
    TextBox4 =Fields!FirstName.Value & " " & Fields!LastName.Value
    TextBox5 =Fields!Role.Value
    TextBox6 =Fields!City.Value
  7. レポートエクスプローラから、[Table1]ノードを選択し、[プロパティ]ウィンドウからLocationプロパティを「0in, 1in」Sizeプロパティを「6in, 0.5in」に設定し、すべてのデータが表示されるように幅を調整します。
  8. [Table1]ノードを選択し、[プロパティ]ウィンドウからDataSetNameプロパティに「DataSet1を入力します。

カスタムデータプロバイダを格納するためのクラスライブラリプロジェクトを追加する

  1. ファイルメニューから[追加]を選択し、[新しいプロジェクト]を選択します。
  2. [新しいプロジェクトの追加]ダイアログでは、[クラスライブラリ]を選択し、プロジェクト名を「CustomDataProvider」に変更します。
  3. ソリューションエクスプローラーから、デフォルトで作成されたクラスを右クリックし、[削除]を選択します。
  4. CustomDataProviderプロジェクトの[参照]を右クリックし、[NuGetパッケージの管理]を選択します。[NuGetパッケージマネージャー]から以下のパッケージをインストールします。
    • GrapeCity.ActiveReports.ja
    • System.Data.Common
  5. CustomDataProviderプロジェクトの[参照]を右クリックし、[参照の追加]を選択します。[参照の追加]ダイアログでは.NETタブから以下の参照を選択します。
    • System.Drawing
    • System.Windows.Forms
  6. CustomDataProviderプロジェクトを右クリックし、[追加]を選択します。[新しいフォルダー]を選択し、フォルダ名を「CSVDataProvider」に変更します。
  7. 追加したフォルダを右クリックし、[追加]を選択します。[クラス]を選択し、ファイル名を「CsvColumn」に変更します。デフォルトスタブを以下のコードに置き換えます。

    Visual Basic

    Visual Basic コード(クラスのデフォルトスタブと置き換えます)
    コードのコピー
    Namespace CSVDataProvider
           'データソース内のフィールドに関する情報を表します。
            Friend Structure CsvColumn
                    Private ReadOnly _fieldName As String
                    Private ReadOnly _dataType As Type
    
                    ' CsvColumnクラスの新しいインスタンスを生成します。
                      ' fieldNameはCsvColumnのインスタンスによって表されるフィールドの名前です。
                      ' dataTypeはCsvColumnのインスタンスによって表されるフィールドの種類です。
                      Public Sub New(fieldName As String, dataType As Type)
                            If fieldName Is Nothing Then
                                    Throw New ArgumentNullException("fieldName")
                            End If
                            If dataType Is Nothing Then
                                    Throw New ArgumentNullException("dataType")
                            End If
                            _fieldName = fieldName
                            _dataType = dataType
                    End Sub
    
    
                    ' CsvColumnのインスタンスによって表されるフィールドの名前を取得します。
                      Public ReadOnly Property FieldName() As String
                            Get
                                    Return _fieldName
                            End Get
                    End Property
    
    
                    ' CsvColumnのインスタンスによって表されるフィールドの種類を取得します。
                      Public ReadOnly Property DataType() As Type
                            Get
                                    Return _dataType
                            End Get
                    End Property
    
    
                    ' CsvColumnのインスタンスを表わす文字列を返します。
                      Public Overrides Function ToString() As String
                            Return [String].Concat(New String() {FieldName, "(", DataType.ToString(), ")"})
                    End Function
    
    
                    ' 2つのCsvColumnのインスタンスが同じかどうかを判定します。
                      ' 指定されたCsvColumnが現在のCsvColumnと同じである場合はTrueを返し、そうではない場合はFalseを返します。
                      Public Overrides Function Equals(obj As Object) As Boolean
                            Dim flag As Boolean
    
                            If TypeOf obj Is CsvColumn Then
                                    flag = Equals(CType(obj, CsvColumn))
                            Else
                                    flag = False
                            End If
                            Return flag
                    End Function
    
                    Private Overloads Function Equals(column As CsvColumn) As Boolean
                            Return column.FieldName = FieldName
                    End Function
    
    
                    ' ハッシュテーブルのようなハッシュアルゴリズムやデータ構造での使用に適した、CsvColumnのハッシュ関数として機能します。
                      ' 現在のCsvColumnインスタンスにハッシュコードを返します。
                      Public Overrides Function GetHashCode() As Integer
                            Return (FieldName.GetHashCode() + DataType.GetHashCode())
                    End Function
            End Structure
    End Namespace
    

    C#

    C#コード(クラスのデフォルトスタブと置き換えます)
    コードのコピー
    using System;
    
    namespace CustomDataProvider.CSVDataProvider
    {
            // データソース内のフィールドに関する情報を表します。
            internal struct CsvColumn
            {
                    private readonly string _fieldName;
                    private readonly Type _dataType;
    
                    // CsvColumnクラスの新しいインスタンスを生成します。
                      // fieldNameはCsvColumnのインスタンスによって表されるフィールドの名前です。
                      // dataTypeはCsvColumnのインスタンスによって表されるフィールドの種類です。
                      public CsvColumn(string fieldName, Type dataType)
                    {
                            if (fieldName == null)
                                    throw new ArgumentNullException("fieldName");
                            if (dataType == null)
                                    throw new ArgumentNullException("dataType");
                            _fieldName = fieldName;
                            _dataType = dataType;
                    }
    
    
                    // CsvColumnのインスタンスによって表されるフィールドの名前を取得します。
                      public string FieldName
                    {
                            get { return _fieldName; }
                    }
    
    
                    //CsvColumnのインスタンスによって表されるフィールドの種類を取得します。
                      public Type DataType
                    {
                            get { return _dataType; }
                    }
    
    
                   //CsvColumnのインスタンスを表わす文字列を返します。
                      public override string ToString()
                    {
                            return String.Concat(new string[] {FieldName, "(", DataType.ToString(), ")"});
                    }
    
    
                    //2つのCsvColumnのインスタンスが同じかどうかを判定します。
                      //指定されたCsvColumnが現在のCsvColumnと同じである場合はTrueを返し、そうではない場合はFalseを返します。
                      public override bool Equals(object obj)
                    {
                            bool flag;
    
                            if (obj is CsvColumn)
                            {
                                    flag = Equals((CsvColumn) obj);
                            }
                            else
                            {
                                    flag = false;
                            }
                            return flag;
                    }
    
                    private bool Equals(CsvColumn column)
                    {
                            return column.FieldName == FieldName;
                    }
    
    
                    //ハッシュテーブルのようなハッシュアルゴリズムやデータ構造での使用に適した、CsvColumnのハッシュ関数として機能します。
                      //現在のCsvColumnインスタンスにハッシュコードを返します。
                      public override int GetHashCode()
                    {
                            return (FieldName.GetHashCode() + DataType.GetHashCode());
                    }
            }
    }
    
  8. CSVDataProviderフォルダを右クリックし、[追加]から[クラス]を選択し、ファイル名を「CsvDataReader」に変更します。デフォルトスタブを以下のコードに置き換えます。

    Visual Basic

    Visual Basicコード(クラスのデフォルトスタブと置き換えます)
    コードのコピー
    Imports System.Text.RegularExpressions
    Imports System.IO
    Imports System.Globalization
    Imports System.Data.Common
    
    Namespace CSVDataProvider
            ''' <summary>
            ''' .NETフレームワークのCSVデータプロバイダの<see cref="DbDataReader"/>を実装する方法を提供します。
            ''' </summary>
            Friend Class CsvDataReader
                    Inherits DbDataReader
                    Private _typeLookup As New Hashtable(New myCultureComparer(New CultureInfo("ja")))
    
                    Private _columnLookup As New Hashtable()
                    Private _columns As Object()
                    Private _textReader As TextReader
                    Private _currentRow As Object()
    
                    '早急な処理を行うために、正規表現をプリコンパイルします。
    
                    'マルチスレッドを避けるために、プロパティは読み取り専用に設定されています。
    
                    Private Shared ReadOnly _rxDataRow As New Regex(",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))", RegexOptions.Compiled)
                    'データ行を解析するために使用されます。
    
                    Private Shared ReadOnly _rxHeaderRow As New Regex("(?<fieldName>(\w*\s*)*)\((?<fieldType>\w*)\)", RegexOptions.Compiled)
                    'ヘッダ行を解析するために使用されます。
                    ''' <summary>
                    ''' </summary>
                    ''' <param name="textReader">データ読み込みに使用される<see cref="TextReader"/>。</param>
                    Public Sub New(textReader As TextReader)
                            _textReader = textReader
                            ParseCommandText()
                    End Sub
    
                    ''' <summary>
                    '''渡されたコマンドのテキストを解析します。
                    ''' </summary>
                    Private Sub ParseCommandText()
                            If _textReader.Peek() = -1 Then
                                    Return
                            End If
                            'コマンドのテキストは空であるか既に末尾にあります。
                            FillTypeLookup()
                            Try
                                    If Not ParseHeader(_textReader.ReadLine()) Then
                                            Throw New InvalidOperationException("フィールド名とデータ型が定義されていません。 CommandTextの先頭行には、フィールド名およびデータ型を追加する必要があります。例: FirstName(string)")
    
                                    End If
                            Catch generatedExceptionName As Exception
                            End Try
                    End Sub
    
                    'ハッシュテーブルは、ヘッダのテキストで使用される文字列値の型を返すために使用されます。
    
                    Private Sub FillTypeLookup()
                            _typeLookup.Add("string", GetType([String]))
                            _typeLookup.Add("byte", GetType([Byte]))
                            _typeLookup.Add("boolean", GetType([Boolean]))
                            _typeLookup.Add("datetime", GetType(DateTime))
                            _typeLookup.Add("decimal", GetType([Decimal]))
                            _typeLookup.Add("double", GetType([Double]))
                            _typeLookup.Add("int16", GetType(Int16))
                            _typeLookup.Add("int32", GetType(Int32))
                            _typeLookup.Add("int", GetType(Int32))
                            _typeLookup.Add("integer", GetType(Int32))
                            _typeLookup.Add("int64", GetType(Int64))
                            _typeLookup.Add("sbyte", GetType([SByte]))
                            _typeLookup.Add("single", GetType([Single]))
                            _typeLookup.Add("time", GetType(DateTime))
                            _typeLookup.Add("date", GetType(DateTime))
                            _typeLookup.Add("uint16", GetType(UInt16))
                            _typeLookup.Add("uint32", GetType(UInt32))
                            _typeLookup.Add("uint64", GetType(UInt64))
                    End Sub
    
                    ''' <summary>
                    ''' ヘッダテキストの文字列から渡された文字列の値に基づいてデータ型を返します。一致しない場合は、文字列型が返されます。
                    ''' </summary>
                    ''' <param name="fieldType">ヘッダコマンドのテキスト文字列からの文字列値。</param>
                    Private Function GetFieldTypeFromString(fieldType As String) As Type
                            If _typeLookup.Contains(fieldType) Then
                                    Return TryCast(_typeLookup(fieldType), Type)
                            End If
                            Return GetType([String])
                    End Function
    
                    ''' <summary>
                    ''' 渡されたコマンドのテキストの先頭行を解析し、フィールド名およびデータ型を作成します。フィールドの情報は、
                    ''' <see cref="CsvColumn"/>構造体に保存され、列情報の項目はArrayListに格納されています。列名は、容易に検索できるハッシュテーブルに
                    ''' 追加します。
                    ''' </summary>
                    ''' <param name="header">すべてのフィールドを含むヘッダ文字列。</param>
                    ''' <returns>ヘッダ文字列を解析できる場合は、True。それ以外の場合は、False。</returns>
                    Private Function ParseHeader(header As String) As Boolean
                            Dim fieldName As String
                            Dim index As Integer = 0
                            If header.IndexOf("(") = -1 Then
                                    Return False
                            End If
    
                            Dim matches As MatchCollection = _rxHeaderRow.Matches(header)
                            _columns = New Object(matches.Count - 1) {}
                            For Each match As Match In matches
                                    fieldName = match.Groups("fieldName").Value
                                    Dim fieldType As Type = GetFieldTypeFromString(match.Groups("fieldType").Value)
                                    _columns.SetValue(New CsvColumn(fieldName, fieldType), index)
                                    _columnLookup.Add(fieldName, index)
                                    index += 1
                            Next
                            Return True
                    End Function
    
                    ''' <summary>
                    ''' 正規表現を使用し、データの行を解析します。データの現在の行となるオブジェクト配列内に情報を保存します。
                    ''' 行でフィールド数が正しくない場合は、例外が発生します。
                    ''' </summary>
                    ''' <param name="dataRow">カンマ区切りのデータ行を表す文字列値。</param>
                    ''' <returns>データ文字列を解析できる場合は、True。それ以外の場合は、False。</returns>
                    Private Function ParseDataRow(dataRow As String) As Boolean
                            Dim index As Integer = 0
                            Dim tempData As String() = _rxDataRow.Split(dataRow)
    
                            _currentRow = New Object(tempData.Length - 1) {}
                            If tempData.Length <> _columns.Length Then
                                    Dim [error] As String = String.Format(CultureInfo.InvariantCulture, "無効な行: ""{0}""。 行ではテーブルヘッダの定義と同じデータ列が含まれていません。", dataRow)
    
                                    Throw New InvalidOperationException([error])
                            End If
                            Dim i As Integer = 0
                            While i < tempData.Length
                                    Dim value As String = tempData(i)
    
                                    If value.Length > 1 Then
                                            If value.IndexOf(""""c, 0) = 0 AndAlso value.IndexOf(""""c, 1) = value.Length - 1 Then
                                                    value = value.Substring(1, value.Length - 2)
                                            End If
                                    End If
                                    _currentRow.SetValue(ConvertValue(GetFieldType(index), value), index)
                                    index += 1
                                    i += 1
                            End While
                            Return True
                    End Function
    
                    ''' <summary>
                    '''フィールド型に基づいてコマンドのテキストからの文字列値を適切なデータ型に変換します。
                    ''' また、String.EmptyまたはSystem.Data.DBNullを返す必要がないかを確認するためにいくつか文字列値のルールをチックします。
                    ''' </summary>
                    ''' <param name="type">現在の列の型は、データが属している.</param>
                    ''' <param name="originalValue">コマンドテキストからの文字列値。</param>
                    ''' <returns>データ型に基づいている変換された文字列を返します。</returns>
                    Private Function ConvertValue(type As Type, originalValue As String) As Object
                            Dim fieldType As Type = type
                            Dim invariantCulture As CultureInfo = CultureInfo.InvariantCulture
                            Try
                                    If originalValue = """""" OrElse originalValue = " " Then
                                            Return String.Empty
                                    End If
                                    If originalValue = "" Then
                                            Return DBNull.Value
                                    End If
                                    If originalValue = "DBNull" Then
                                            Return DBNull.Value
                                    End If
                                    If fieldType = GetType([String]) Then
                                            Return originalValue.Trim()
                                    End If
                                    If fieldType = GetType(Int32) Then
                                            Return Convert.ToInt32(originalValue, invariantCulture)
                                    End If
                                    If fieldType = GetType([Boolean]) Then
                                            Return Convert.ToBoolean(originalValue, invariantCulture)
                                    End If
                                    If fieldType = GetType(DateTime) Then
                                            Return Convert.ToDateTime(originalValue, invariantCulture)
                                    End If
                                    If fieldType = GetType([Decimal]) Then
                                            Return Convert.ToDecimal(originalValue, invariantCulture)
                                    End If
                                    If fieldType = GetType([Double]) Then
                                            Return Convert.ToDouble(originalValue, invariantCulture)
                                    End If
                                    If fieldType = GetType(Int16) Then
                                            Return Convert.ToInt16(originalValue, invariantCulture)
                                    End If
                                    If fieldType = GetType(Int64) Then
                                            Return Convert.ToInt64(originalValue, invariantCulture)
                                    End If
                                    If fieldType = GetType([Single]) Then
                                            Return Convert.ToSingle(originalValue, invariantCulture)
                                    End If
                                    If fieldType = GetType([Byte]) Then
                                            Return Convert.ToByte(originalValue, invariantCulture)
                                    End If
                                    If fieldType = GetType([SByte]) Then
                                            Return Convert.ToSByte(originalValue, invariantCulture)
                                    End If
                                    If fieldType = GetType(UInt16) Then
                                            Return Convert.ToUInt16(originalValue, invariantCulture)
                                    End If
                                    If fieldType = GetType(UInt32) Then
                                            Return Convert.ToUInt32(originalValue, invariantCulture)
                                    End If
                                    If fieldType = GetType(UInt64) Then
                                            Return Convert.ToUInt64(originalValue, invariantCulture)
                                    End If
                            Catch e As Exception
                                    Throw New InvalidOperationException(String.Format("入力値 '{0}'を'{1}'型に変換できません。", originalValue, type), e)
                            End Try
                            '一致しない場合は、DBNullを返します。
    
                            Return DBNull.Value
                    End Function
    
    
                    ''' <summary>
                    ''' <see cref="CsvDataReader"/>を次のレコードに移動します。
                    ''' </summary>
                    ''' <returns>他の行がある場合はTrue、それ以外の場合はFalse。</returns>
                    Public Overrides Function Read() As Boolean
                            If _textReader.Peek() > -1 Then
                                    ParseDataRow(_textReader.ReadLine())
                            Else
                                    Return False
                            End If
    
                            Return True
                    End Function
    
                    ''' <summary>
                    '''<see cref="CsvDataReader"/>により使用されたリソースを解放します。
                    ''' </summary>
                    Public Shadows Sub Dispose()
                            Dispose(True)
                            GC.SuppressFinalize(Me)
                    End Sub
    
                    Protected Shadows Sub Dispose(disposing As Boolean)
                            If disposing Then
                                    If _textReader IsNot Nothing Then
                                            _textReader.Close()
                                    End If
                            End If
    
                            _typeLookup = Nothing
                            _columnLookup = Nothing
                            _columns = Nothing
                            _currentRow = Nothing
                    End Sub
    
                    ''' <summary>
                    ''' Objectがガベージ コレクションにより収集される前に、その Object がリソースを解放し、その他のクリーンアップ操作を実行できるようにします。
                    ''' </summary>
                    Protected Overrides Sub Finalize()
                            Try
                                    Dispose(False)
                            Finally
                                    MyBase.Finalize()
                            End Try
                    End Sub
    
                    ''' <summary>
                    ''' 現在の行の列数を取得します。
                    ''' </summary>
                    Public Overrides ReadOnly Property FieldCount() As Integer
                            Get
                                    If _columns Is Nothing Then
                                            _columns = New Object(-1) {}
                                    End If
                                    Return _columns.Length
                            End Get
                    End Property
    
                    Public Overrides ReadOnly Property Depth() As Integer
                            Get
                                    Return 0
                            End Get
                    End Property
    
                    Public Overrides ReadOnly Property IsClosed() As Boolean
                            Get
                                    Return False
                            End Get
                    End Property
    
                    Public Overrides ReadOnly Property RecordsAffected() As Integer
                            Get
                                    Return 0
                            End Get
                    End Property
    
                    Default Public Overrides ReadOnly Property Item(name As String) As Object
                            Get
                                    Return Me(GetOrdinal(name).ToString())
                            End Get
                    End Property
    
                    Default Public Overrides ReadOnly Property Item(i As Integer) As Object
                            Get
                                    Return GetValue(i)
                            End Get
                    End Property
    
                    Public Overrides ReadOnly Property HasRows As Boolean
                            Get
                                    Throw New NotImplementedException()
                            End Get
                    End Property
    
                    ''' <summary>
                    ''' 指定したフィールドの値を返します。
                    ''' </summary>
                    ''' <param name="ordinal">検索するフィールドのインデックス。 </param>
                    ''' <returns>フィールドの値を返す<see cref="Object"/>。</returns>
                    Public Overrides Function GetFieldType(ordinal As Integer) As Type
                            If ordinal > _columns.Length - 1 Then
                                    Return Nothing
                            End If
    
                            Return CType(_columns.GetValue(ordinal), CsvColumn).DataType
                    End Function
    
                    ''' <summary>
                    ''' 指定したフィールドの値を返します。
                    ''' </summary>
                    ''' <param name="i">検索するフィールドのインデックス。 </param>
                    '''フィールドの名前を返します。値はない場合は、空の文字列("")を返します。
                    Public Overrides Function GetName(i As Integer) As String
                            If i > _columns.Length - 1 Then
                                    Return String.Empty
                            End If
    
                            Return CType(_columns.GetValue(i), CsvColumn).FieldName
                    End Function
    
                    Public Overrides Function GetOrdinal(name As String) As Integer
                            Dim value As Object = _columnLookup(name)
                            If value Is Nothing Then
                                    Throw New IndexOutOfRangeException("name")
                            End If
                            Return CType(value, Integer)
                    End Function
    
                    ''' <summary>
                    ''' 指定したフィールドの値を返します。
                    ''' </summary>
                    ''' <param name="i">検索するフィールドのインデックス。 </param>
                    ''' <returns>フィールドの値を返す<see cref="Object"/>。</returns>
                    Public Overrides Function GetValue(i As Integer) As Object
                            If i > _columns.Length - 1 Then
                                    Return Nothing
                            End If
    
                            Return _currentRow.GetValue(i)
                    End Function
    
                    Public Overrides Sub Close()
                    End Sub
    
                    Public Overrides Function GetSchemaTable() As System.Data.DataTable
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function NextResult() As Boolean
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetDataTypeName(i As Integer) As String
                            Return GetFieldType(i).ToString()
                    End Function
    
                    Public Overrides Function GetValues(values As Object()) As Integer
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetBoolean(i As Integer) As Boolean
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetByte(i As Integer) As Byte
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetBytes(i As Integer, fieldOffset As Long, buffer As Byte(), bufferoffset As Integer, length As Integer) As Long
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetChar(i As Integer) As Char
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetChars(i As Integer, fieldoffset As Long, buffer As Char(), bufferoffset As Integer, length As Integer) As Long
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetGuid(i As Integer) As Guid
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetInt16(i As Integer) As Short
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetInt32(i As Integer) As Integer
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetInt64(i As Integer) As Long
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetFloat(i As Integer) As Single
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetDouble(i As Integer) As Double
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetString(i As Integer) As String
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetDecimal(i As Integer) As Decimal
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetDateTime(i As Integer) As DateTime
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function IsDBNull(i As Integer) As Boolean
                            Throw New NotImplementedException()
                    End Function
    
                    Public Overrides Function GetEnumerator() As IEnumerator
                            Throw New NotImplementedException()
                    End Function
    
    #Region "EqualityComparer"
    
                    Private Class myCultureComparer
                            Implements IEqualityComparer
                            Public myComparer As CaseInsensitiveComparer
    
                            Public Sub New()
                                    myComparer = CaseInsensitiveComparer.DefaultInvariant
                            End Sub
    
                            Public Sub New(myCulture As CultureInfo)
                                    myComparer = New CaseInsensitiveComparer(myCulture)
                            End Sub
    
                            Public Shadows Function Equals(x As Object, y As Object) As Boolean Implements IEqualityComparer.Equals
                                    If myComparer.Compare(x, y) = 0 Then
                                            Return True
                                    Else
                                            Return False
                                    End If
                            End Function
    
                            Public Shadows Function GetHashCode(obj As Object) As Integer Implements IEqualityComparer.GetHashCode
                                    Return obj.ToString().ToLower().GetHashCode()
                            End Function
                    End Class
    
    #End Region
            End Class
    End Namespace
    

    C#

    C#コード(クラスのデフォルトスタブと置き換えます)
    コードのコピー
    using System;
    using System.Collections;
    using System.Data.Common;
    using System.Globalization;
    using System.IO;
    using System.Text.RegularExpressions;
    
    namespace CustomDataProvider.CSVDataProvider
    {
            /// <summary>
            /// .NETフレームワークのCSVデータプロバイダの<see cref="DbDataReader"/>を実装する方法を提供します。
            /// </summary>
            internal class CsvDataReader : DbDataReader
            {
                    private Hashtable _typeLookup = new Hashtable(new myCultureComparer(new CultureInfo("ja")));
    
                    private Hashtable _columnLookup = new Hashtable();
                    private object[] _columns;
                    private TextReader _textReader;
                    private object[] _currentRow;
    
                    //早急な処理を行うために、正規表現をプリコンパイルします。
    
                    //マルチスレッドを避けるために、プロパティは読み取り専用に設定されています。
    
                    private static readonly Regex _rxDataRow = new Regex(@",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))", RegexOptions.Compiled);
                    //データ行を解析するために使用されます。
    
                    private static readonly Regex _rxHeaderRow =
                            new Regex(@"(?<fieldName>(\w*\s*)*)\((?<fieldType>\w*)\)", RegexOptions.Compiled); //ヘッダ行を解析するために使用されます。
    
                    /// <summary>
                    /// </summary>
                    /// <param name="textReader">データ読み込みに使用される<see cref="TextReader"/>。</param>
                    public CsvDataReader(TextReader textReader)
                    {
                            _textReader = textReader;
                            ParseCommandText();
                    }
    
                    /// <summary>
                    ///渡されたコマンドのテキストを解析します。
                    /// </summary>
                    private void ParseCommandText()
                    {
                            if (_textReader.Peek() == -1)
                                    return; //コマンドのテキストは空であるか既に末尾にあります。
    
                            FillTypeLookup();
                            try
                            {
                                    if (!ParseHeader(_textReader.ReadLine()))
                                            throw new InvalidOperationException("フィールド名とデータ型が定義されていません。 CommandTextの先頭行には、フィールド名およびデータ型を追加する必要があります。例: FirstName(string)");
    
                            }
                            catch (Exception)
                            {
                            }
                    }
    
                    //ハッシュテーブルは、ヘッダのテキストで使用される文字列値の型を返すために使用されます。
    
                    private void FillTypeLookup()
                    {
                            _typeLookup.Add("string", typeof(String));
                            _typeLookup.Add("byte", typeof(Byte));
                            _typeLookup.Add("boolean", typeof(Boolean));
                            _typeLookup.Add("datetime", typeof(DateTime));
                            _typeLookup.Add("decimal", typeof(Decimal));
                            _typeLookup.Add("double", typeof(Double));
                            _typeLookup.Add("int16", typeof(Int16));
                            _typeLookup.Add("int32", typeof(Int32));
                            _typeLookup.Add("int", typeof(Int32));
                            _typeLookup.Add("integer", typeof(Int32));
                            _typeLookup.Add("int64", typeof(Int64));
                            _typeLookup.Add("sbyte", typeof(SByte));
                            _typeLookup.Add("single", typeof(Single));
                            _typeLookup.Add("time", typeof(DateTime));
                            _typeLookup.Add("date", typeof(DateTime));
                            _typeLookup.Add("uint16", typeof(UInt16));
                            _typeLookup.Add("uint32", typeof(UInt32));
                            _typeLookup.Add("uint64", typeof(UInt64));
                    }
    
                    /// <summary>
                    /// ヘッダテキストの文字列から渡された文字列の値に基づいてデータ型を返します。一致しない場合は、文字列型が返されます。
                    /// </summary>
                    /// <param name="fieldType">ヘッダコマンドのテキスト文字列からの文字列値。</param>
                    private Type GetFieldTypeFromString(string fieldType)
                    {
                            if (_typeLookup.Contains(fieldType))
                                    return _typeLookup[fieldType] as Type;
                            return typeof(String);
                    }
    
                    /// <summary>
                    /// 渡されたコマンドのテキストの先頭行を解析し、フィールド名およびデータ型を作成します。フィールドの情報は、
                    /// <see cref="CsvColumn"/>構造体に保存され、列情報の項目はArrayListに格納されています。列名は、容易に検索できるハッシュテーブルに
                    /// 追加します。
                    /// </summary>
                    /// <param name="header">すべてのフィールドを含むヘッダ文字列。</param>
                    /// <returns>ヘッダ文字列を解析できる場合は、True。それ以外の場合は、False。</returns>
                    private bool ParseHeader(string header)
                    {
                            string fieldName;
                            int index = 0;
                            if (header.IndexOf("(") == -1)
                            {
                                    return false;
                            }
    
                            MatchCollection matches = _rxHeaderRow.Matches(header);
                            _columns = new object[matches.Count];
                            foreach (Match match in matches)
                            {
                                    fieldName = match.Groups["fieldName"].Value;
                                    Type fieldType = GetFieldTypeFromString(match.Groups["fieldType"].Value);
                                    _columns.SetValue(new CsvColumn(fieldName, fieldType), index);
                                    _columnLookup.Add(fieldName, index);
                                    index++;
                            }
                            return true;
                    }
    
                    /// <summary>
                    /// 正規表現を使用し、データの行を解析します。データの現在の行となるオブジェクト配列内に情報を保存します。
                    /// 行でフィールド数が正しくない場合は、例外が発生します。
                    /// </summary>
                    /// <param name="dataRow">カンマ区切りのデータ行を表す文字列値。</param>
                    /// <returns>データ文字列を解析できる場合は、True。それ以外の場合は、False。</returns>
                    private bool ParseDataRow(string dataRow)
                    {
                            int index = 0;
                            string[] tempData = _rxDataRow.Split(dataRow);
    
                            _currentRow = new object[tempData.Length];
                            if (tempData.Length != _columns.Length)
                            {
                                    string error = string.Format(CultureInfo.InvariantCulture, "無効な行:\"{0}\"。 行ではテーブルヘッダの定義と同じデータ列が含まれていません。", dataRow);
    
                                    throw new InvalidOperationException(error);
                            }
                            for (int i = 0; i < tempData.Length; i++)
                            {
                                    string value = tempData[i];
    
                                    if (value.Length > 1)
                                    {
                                            if (value.IndexOf('"', 0) == 0 && value.IndexOf('"', 1) == value.Length - 1)
                                                    value = value.Substring(1, value.Length - 2);
                                    }
                                    _currentRow.SetValue(ConvertValue(GetFieldType(index), value), index);
                                    index++;
                            }
                            return true;
                    }
    
                    /// <summary>
                    ///フィールド型に基づいてコマンドのテキストからの文字列値を適切なデータ型に変換します。
                    /// また、String.EmptyまたはSystem.Data.DBNullを返す必要がないかを確認するためにいくつか文字列値のルールをチックします。
                    /// </summary>
                    /// <param name="type">現在の列の型は、データが属している.</param>
                    /// <param name="originalValue">コマンドテキストからの文字列値。</param>
                    /// <returns>データ型に基づいている変換された文字列を返します。</returns>
                    private object ConvertValue(Type type, string originalValue)
                    {
                            Type fieldType = type;
                            CultureInfo invariantCulture = CultureInfo.InvariantCulture;
                            try
                            {
                                    if (originalValue == "\"\"" || originalValue == " ")
                                            return string.Empty;
                                    if (originalValue == "")
                                            return DBNull.Value;
                                    if (originalValue == "DBNull")
                                            return DBNull.Value;
                                    if (fieldType == typeof(String))
                                            return originalValue.Trim();
                                    if (fieldType == typeof(Int32))
                                            return Convert.ToInt32(originalValue, invariantCulture);
                                    if (fieldType == typeof(Boolean))
                                            return Convert.ToBoolean(originalValue, invariantCulture);
                                    if (fieldType == typeof(DateTime))
                                            return Convert.ToDateTime(originalValue, invariantCulture);
                                    if (fieldType == typeof(Decimal))
                                            return Convert.ToDecimal(originalValue, invariantCulture);
                                    if (fieldType == typeof(Double))
                                            return Convert.ToDouble(originalValue, invariantCulture);
                                    if (fieldType == typeof(Int16))
                                            return Convert.ToInt16(originalValue, invariantCulture);
                                    if (fieldType == typeof(Int64))
                                            return Convert.ToInt64(originalValue, invariantCulture);
                                    if (fieldType == typeof(Single))
                                            return Convert.ToSingle(originalValue, invariantCulture);
                                    if (fieldType == typeof(Byte))
                                            return Convert.ToByte(originalValue, invariantCulture);
                                    if (fieldType == typeof(SByte))
                                            return Convert.ToSByte(originalValue, invariantCulture);
                                    if (fieldType == typeof(UInt16))
                                            return Convert.ToUInt16(originalValue, invariantCulture);
                                    if (fieldType == typeof(UInt32))
                                            return Convert.ToUInt32(originalValue, invariantCulture);
                                    if (fieldType == typeof(UInt64))
                                            return Convert.ToUInt64(originalValue, invariantCulture);
                            }
                            catch (Exception e)
                            {
                                    throw new InvalidOperationException(string.Format("入力値 \'{0}\'を\'{1}\'型に変換できません。", originalValue, type), e);
                            }
                            //一致しない場合は、DBNullを返します。
    
                            return DBNull.Value;
                    }
    
    
                    /// <summary>
                    /// <see cref="CsvDataReader"/>を次のレコードに移動します。
                    /// </summary>
                    /// <returns>他の行がある場合はTrue、それ以外の場合はFalse。</returns>
                    public override bool Read()
                    {
                            if (_textReader.Peek() > -1)
                                    ParseDataRow(_textReader.ReadLine());
                            else
                                    return false;
    
                            return true;
                    }
    
                    /// <summary>
                    ///<see cref="CsvDataReader"/>により使用されたリソースを解放します。
                    /// </summary>
                    public new void Dispose()
                    {
                            Dispose(true);
                            GC.SuppressFinalize(this);
                    }
    
                    protected override void Dispose(bool disposing)
                    {
                            if (disposing)
                            {
                                    if (_textReader != null)
                                            _textReader.Close();
                            }
    
                            _typeLookup = null;
                            _columnLookup = null;
                            _columns = null;
                            _currentRow = null;
                    }
    
                    /// <summary>
                    /// Objectがガベージ コレクションにより収集される前に、その Object がリソースを解放し、その他のクリーンアップ操作を実行できるようにします。
                    /// </summary>
                    ~CsvDataReader()
                    {
                            Dispose(false);
                    }
    
                    /// <summary>
                    /// 現在の行の列数を取得します。
                    /// </summary>
                    public override int FieldCount
                    {
                            get
                            {
                                    if (_columns == null)
                                            _columns = new object[0];
                                    return _columns.Length;
                            }
                    }
    
                    public override int Depth
                    {
                            get { return 0; }
                    }
    
                    public override bool IsClosed
                    {
                            get { return false; }
                    }
    
                    public override int RecordsAffected
                    {
                            get { return 0; }
                    }
    
                    public override bool HasRows
                    {
                            get
                            {
                                    throw new NotImplementedException();
                            }
                    }
    
                    public override object this[string name]
                    {
                            get { return this[GetOrdinal(name).ToString()]; }
                    }
    
                    public override object this[int i]
                    {
                            get { return GetValue(i); }
                    }
    
                    /// <summary>
                    /// 指定したフィールドの値を返します。
                    /// </summary>
                    /// <param name="i">検索するフィールドのインデックス。 </param>
                    /// <returns>フィールドの値を返す<see cref="Object"/>。</returns>
                    public override Type GetFieldType(int ordinal)
                    {
                            if (ordinal > _columns.Length - 1)
                                    return null;
    
                            return ((CsvColumn)_columns.GetValue(ordinal)).DataType;
                    }
    
                    /// <summary>
                    /// 指定したフィールドの値を返します。
                    /// </summary>
                    /// <param name="i">検索するフィールドのインデックス。 </param>       
                    ///フィールドの名前を返します。値はない場合は、空の文字列("")を返します。
                    public override string GetName(int i)
                    {
                            if (i > _columns.Length - 1)
                                    return string.Empty;
    
                            return ((CsvColumn)_columns.GetValue(i)).FieldName;
                    }
    
                    public override int GetOrdinal(string name)
                    {
                            object value = _columnLookup[name];
                            if (value == null)
                                    throw new IndexOutOfRangeException("name");
                            return (int)value;
                    }
    
                    /// <summary>
                    /// 指定したフィールドの値を返します。
                    /// </summary>
                    /// <param name="i">検索するフィールドのインデックス。 </param>
                    /// <returns>フィールドの値を返す<see cref="Object"/>。</returns>
                    public override object GetValue(int i)
                    {
                            if (i > _columns.Length - 1)
                                    return null;
    
                            return _currentRow.GetValue(i);
                    }
    
                    public override void Close()
                    { }
    
                    public override System.Data.DataTable GetSchemaTable()
                    {
                            throw new NotImplementedException();
                    }
    
                    public override bool NextResult()
                    {
                            throw new NotImplementedException();
                    }
    
                    public override string GetDataTypeName(int i)
                    {
                            return GetFieldType(i).ToString();
                    }
    
                    public override int GetValues(object[] values)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override bool GetBoolean(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override byte GetByte(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override char GetChar(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override Guid GetGuid(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override short GetInt16(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override int GetInt32(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override long GetInt64(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override float GetFloat(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override double GetDouble(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override string GetString(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override decimal GetDecimal(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override DateTime GetDateTime(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override bool IsDBNull(int i)
                    {
                            throw new NotImplementedException();
                    }
    
                    public override IEnumerator GetEnumerator()
                    {
                            throw new NotImplementedException();
                    }
    
                    #region EqualityComparer
    
                    class myCultureComparer : IEqualityComparer
                    {
                            public CaseInsensitiveComparer myComparer;
    
                            public myCultureComparer()
                            {
                                    myComparer = CaseInsensitiveComparer.DefaultInvariant;
                            }
    
                            public myCultureComparer(CultureInfo myCulture)
                            {
                                    myComparer = new CaseInsensitiveComparer(myCulture);
                            }
    
                            public new bool Equals(object x, object y)
                            {
                                    if (myComparer.Compare(x, y) == 0)
                                    {
                                            return true;
                                    }
                                    else
                                    {
                                            return false;
                                    }
                            }
    
                            public int GetHashCode(object obj)
                            {
                                    return obj.ToString().ToLower().GetHashCode();
                            }
                    }
    
                    #endregion
            }
    }
    
  9. CSVDataProviderフォルダを右クリックし、[追加]から[クラス]を選択してファイル名を「CsvCommand」に変更します。デフォルトスタブを以下のコードに置き換えます。(この時点ではエラーが表示されますが、CsvConnectionクラスを追加した後に解消されます) 

    Visual Basic

    Visual Basicコード(クラスのデフォルトスタブと置き換えます)
    コードのコピー
    Imports System.IO
    Imports System.Data.Common
    Namespace CSVDataProvider
    
            ''' <summary>
            '''.NETフレームワークのCSVデータプロバイダの<see cref="DbCommand"/>を実装する方法を提供します。
            ''' </summary>
            Public NotInheritable Class CsvCommand
                    Inherits DbCommand
                    Private _commandText As String
                    Private _connection As DbConnection
                    Private _commandTimeout As Integer
                    Private _commandType As CommandType
    
                    ''' <summary>
                    ''' <see cref="CsvCommand"/>クラスの新しいインスタンスを作成します。
                    ''' </summary>
                    Public Sub New()
                            Me.New(String.Empty)
                    End Sub
    
                    ''' <summary>
                    ''' コマンドのテキストとともに<see cref="CsvCommand"/>クラスの新しいインスタンスを作成します。
                    ''' </summary>
                    ''' <param name="commandText">コマンドのテキスト。</param>
                    Public Sub New(commandText As String)
                            Me.New(commandText, Nothing)
                    End Sub
    
                    ''' <summary>
                    ''' コマンドのテキストとともに<see cref="CsvCommand"/>クラスの新しいインスタンスを作成します。<see cref="CsvConnection"/>.
                    ''' </summary>
                    ''' <param name="commandText">コマンドのテキスト。</param>>
                    ''' <param name="connection">データソースへの接続を表す<see cref="CsvConnection"/>。</param>
                    Public Sub New(commandText As String, connection As CsvConnection)
                            _commandText = commandText
                            _connection = connection
                    End Sub
    
                    ''' <summary>
                    ''' データソースで実行するコマンドを取得または設定します。
                    ''' </summary>
                    Public Overrides Property CommandText() As String
                            Get
                                    Return _commandText
                            End Get
                            Set
                                    _commandText = Value
                            End Set
                    End Property
    
                    ''' <summary>
                    ''' コマンドの実行を終了して、エラーを生成するまでの待機時間を取得または設定します。
                    ''' </summary>
                    Public Overrides Property CommandTimeout() As Integer
                            Get
                                    Return _commandTimeout
                            End Get
                            Set
                                    _commandTimeout = Value
                            End Set
                    End Property
    
                    ''' <summary>
                    ''' <see cref="CommandText"/>プロパティの解釈方法を示す値を取得または設定します。
                    ''' </summary>
                    ''' <remarks>We don't use it for Csv Data Provider.</remarks> 
                    Public Overrides Property CommandType() As CommandType
                            Get
                                    Return _commandType
                            End Get
                            Set
                                    _commandType = Value
                            End Set
                    End Property
    
                    ''' <summary>
                    ''' <see cref="CsvConnection"/>に<see cref="CommandText"/>を送信し、<see cref="CommandBehavior"/>の1つの値を使用し、<see cref="CsvDataReader"/>を作成します。
                    ''' </summary>
                    ''' <param name="behavior"><see cref="CommandBehavior"/>値の1つ。</param>
                    ''' <returns><see cref="CsvDataReader"/>のオブジェクト。</returns>
                    Protected Overrides Function ExecuteDbDataReader(behavior As CommandBehavior) As DbDataReader
                            Return New CsvDataReader(New StringReader(_commandText))
                    End Function
    
                    ''' <summary>
                    '''定数に拡張されたパラメータを持つコマンドのテキストを返します。
                    ''' </summary>
                    ''' <returns>定数に拡張されたパラメータを持つコマンドのテキストを表す文字列。</returns>
                    Public Function GenerateRewrittenCommandText() As String
                            Return _commandText
                    End Function
    
                    ''' <summary>
                    ''' <see cref="CsvConnection"/>に<see cref="CommandText"/>を送信し、<see cref="CsvDataReader"/>を作成します。
                    ''' </summary>
                    ''' <returns><see cref="CsvDataReader"/>のオブジェクト。</returns>
                    Public Shadows Function ExecuteReader() As IDataReader
                            Return MyBase.ExecuteReader(CommandBehavior.SchemaOnly)
                    End Function
    
                    Public Overrides Property UpdatedRowSource() As UpdateRowSource
                            Get
                                    Return UpdateRowSource.None
                            End Get
                            Set
                            End Set
                    End Property
    
                    Protected Overrides Property DbConnection As DbConnection
                            Get
                                    Return _connection
                            End Get
                            Set(value As DbConnection)
                                    _connection = value
                            End Set
                    End Property
    
                    Protected Overrides ReadOnly Property DbParameterCollection As DbParameterCollection
                            Get
                                    Throw New NotImplementedException()
                            End Get
                    End Property
    
                    Protected Overrides Property DbTransaction As DbTransaction
                            Get
                                    Throw New NotImplementedException()
                            End Get
                            Set(value As DbTransaction)
                                    Throw New NotImplementedException()
                            End Set
                    End Property
    
                    Public Overrides Property DesignTimeVisible As Boolean
                            Get
                                    Throw New NotImplementedException()
                            End Get
                            Set(value As Boolean)
                                    Throw New NotImplementedException()
                            End Set
                    End Property
    
                    Public Overrides Sub Cancel()
                            'do nothing
                    End Sub
    
                    Public Shadows Function CreateParameter() As IDbDataParameter
                            'do nothing
                            Return Nothing
                    End Function
    
    
                    ''' <summary>
                    ''' <see cref="CsvCommand"/>により使用されたリソースを解放します。
                    ''' </summary>
                    Public Shadows Sub Dispose()
                            Dispose(True)
                            GC.SuppressFinalize(Me)
                    End Sub
    
                    Protected Shadows Sub Dispose(disposing As Boolean)
                            If disposing Then
                                    If _connection IsNot Nothing Then
                                            _connection.Dispose()
                                            _connection = Nothing
                                    End If
                            End If
                    End Sub
    
                    Public Overrides Sub Prepare()
                            'do nothing
                    End Sub
    
                    Public Overrides Function ExecuteNonQuery() As Integer
                            Return 0
                    End Function
    
                    Public Overrides Function ExecuteScalar() As Object
                            'do nothing
                            Return Nothing
                    End Function
    
                    Protected Overrides Function CreateDbParameter() As DbParameter
                            Throw New NotImplementedException()
                    End Function
            End Class
    End Namespace
    

    C#

    C# コード(クラスのデフォルトスタブと置き換えます)
    コードのコピー
    using System;
    using System.Data;
    using System.Data.Common;
    using System.IO;
    
    
    namespace CustomDataProvider.CSVDataProvider
    {
            /// <summary>
            ///.NETフレームワークのCSVデータプロバイダの<see cref="IDbCommand"/>を実装する方法を提供します。
            /// </summary>
            public sealed class CsvCommand : DbCommand
            {
                    private string _commandText;
                    private DbConnection _connection;
                    private int _commandTimeout;
                    private CommandType _commandType;
    
                    /// <summary>
                    /// <see cref="CsvCommand"/>クラスの新しいインスタンスを作成します。
                    /// </summary>
                    public CsvCommand()
                            : this(string.Empty)
                    {
                    }
    
                    /// <summary>
                    /// コマンドのテキストとともに<see cref="CsvCommand"/>クラスの新しいインスタンスを作成します。
                    /// </summary>
                    /// <param name="commandText">コマンドのテキスト。</param>
                    public CsvCommand(string commandText)
                            : this(commandText, null)
                    {
                    }
    
                    /// <summary>
                    /// コマンドのテキストとともに<see cref="CsvCommand"/>クラスの新しいインスタンスを作成します。<see cref="CsvConnection"/>.
                    /// </summary>
                    /// <param name="commandText">コマンドのテキスト。</ PARAM>
                    /// <param name="connection">データソースへの接続を表す<see cref="CsvConnection"/>。</ PARAM>
                    public CsvCommand(string commandText, CsvConnection connection)
                    {
                            _commandText = commandText;
                            _connection = connection;
                    }
    
                    /// <summary>
                    /// データソースで実行するコマンドを取得または設定します。
                    /// </summary>
                    public override string CommandText
                    {
                            get { return _commandText; }
                            set { _commandText = value; }
                    }
    
                    /// <summary>
                    /// コマンドの実行を終了して、エラーを生成するまでの待機時間を取得または設定します。
                    /// </summary>
                    public override int CommandTimeout
                    {
                            get { return _commandTimeout; }
                            set { _commandTimeout = value; }
                    }
    
                    /// <summary>
                    /// <see cref="CommandText"/>プロパティの解釈方法を示す値を取得または設定します。
                    /// </summary>
                    /// <remarks>We don't use it for Csv Data Provider.</remarks> 
                    public override CommandType CommandType
                    {
                            get { return _commandType; }
                            set { _commandType = value; }
                    }
    
                    /// <summary>
                    /// <see cref="CsvConnection"/>に<see cref="CommandText"/>を送信し、<see cref="CommandBehavior"/>の1つの値を使用し、<see cref="CsvDataReader"/>を作成します。
                    /// </summary>
                    /// <param name="behavior"><see cref="CommandBehavior"/>値の1つ。</param>
                    /// <returns><see cref="CsvDataReader"/>のオブジェクト。</returns>
                    protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
                    {
                            return new CsvDataReader(new StringReader(_commandText));
                    }
    
                    /// <summary>
                    ///定数に拡張されたパラメータを持つコマンドのテキストを返します。
                    /// </summary>
                    /// <returns>定数に拡張されたパラメータを持つコマンドのテキストを表す文字列。</returns>
                    public string GenerateRewrittenCommandText()
                    {
                            return _commandText;
                    }
    
                    /// <summary>
                    /// <see cref="CsvConnection"/>に<see cref="CommandText"/>を送信し、<see cref="CsvDataReader"/>を作成します。
                    /// </summary>
                    /// <returns><see cref="CsvDataReader"/>のオブジェクト。</returns>
                    public new IDataReader ExecuteReader()
                    {
                            return ExecuteReader(CommandBehavior.SchemaOnly);
                    }
    
                    public override UpdateRowSource UpdatedRowSource
                    {
                            get { return UpdateRowSource.None; }
                            set { }
                    }
    
                    protected override DbConnection DbConnection
                    {
                            get { return _connection; }
                            set { _connection = value; }
                    }
    
                    protected override DbParameterCollection DbParameterCollection
                    {
                            get
                            {
                                    throw new NotImplementedException();
                            }
                    }
    
                    protected override DbTransaction DbTransaction
                    {
                            get
                            {
                                    throw new NotImplementedException();
                            }
                            set
                            {
                                    throw new NotImplementedException();
                            }
                    }
    
                    public override bool DesignTimeVisible
                    {
                            get
                            {
                                    throw new NotImplementedException();
                            }
                            set
                            {
                                    throw new NotImplementedException();
                            }
                    }
    
                    public override void Cancel()
                    {
                            //do nothing
                    }
    
                    public new IDbDataParameter CreateParameter()
                    {
                            //do nothing
                            return null;
                    }
    
    
                    /// <summary>
                    /// <see cref="CsvCommand"/>により使用されたリソースを解放します。
                    /// </summary>
                    public new void Dispose()
                    {
                            Dispose(true);
                            GC.SuppressFinalize(this);
                    }
    
                    protected override void Dispose(bool disposing)
                    {
                            if (disposing)
                            {
                                    if (_connection != null)
                                    {
                                            _connection.Dispose();
                                            _connection = null;
                                    }
                            }
                    }
    
                    public override void Prepare()
                    {
                            //do nothing
                    }
    
                    public override int ExecuteNonQuery()
                    {
                            return 0;
                    }
    
                    public override object ExecuteScalar()
                    {
                            //do nothing
                            return null;
                    }
    
                    protected override DbParameter CreateDbParameter()
                    {
                            throw new NotImplementedException();
                    }
            }
    }
    
    
  10. CSVDataProviderフォルダを右クリックし、[追加]から[クラス]を選択し、ファイル名を「CsvConnection」に変更します。デフォルトスタブを以下のコードに置き換えます。

    Visual Basic

    Visual Basicコード(クラスのデフォルトスタブと置き換えます)
    コードのコピー
    Imports System.Data.Common
    Imports System.Data
    Imports System.Collections.Specialized
    Imports System
    
    Namespace CSVDataProvider
            ''' <summary>
            ''' .NETフレームワークのCSVデータプロバイダの<see cref="DbConnection"/>を実装する方法を提供します。
            ''' </summary>
            Public NotInheritable Class CsvConnection
                    Inherits DbConnection
                    Private ReadOnly _localizedName As String
    
                    ''' <summary>
                    ''' <see cref="CsvConnection"/>クラスの新しいインスタンスを作成します。
                    ''' </summary>
                    Public Sub New()
                            _localizedName = "Csv"
                    End Sub
    
                    ''' <summary>
                    ''' <see cref="CsvConnection"/>クラスの新しいインスタンスを作成します。
                    ''' </summary>
                    '''<param name="localizeName"><see cref="CsvConnection"/>のインスタンスのローカライズされた名前。</param>
                    Public Sub New(localizeName As String)
                            _localizedName = localizeName
                    End Sub
    
                    ''' <summary>
                    ''' データソースへの接続を開くために使用される文字列を取得または設定します。
                    ''' </summary>
                    ''' <remarks>Csvデータプロバイダに対する使用されません。</remarks>
                    Public Overrides Property ConnectionString() As String
                            Get
                                    Return String.Empty
                            End Get
                            Set
                            End Set
                    End Property
    
                    ''' <summary>
                    ''' 接続の実行を終了して、エラーを生成するまでの待機時間を取得します。
                    ''' </summary>
                    ''' <remarks>Csvデータプロバイダに対する使用されません。</remarks>
                    Public Overrides ReadOnly Property ConnectionTimeout() As Integer
                            Get
                                    Throw New NotImplementedException()
                            End Get
                    End Property
    
                    ''' <summary>
                    '''データソースのトランザクションを開始します。
                    ''' </summary>
                    ''' 新しいトランザクションを表すオブジェクト。
                    ''' <remarks>Csvデータプロバイダに対する使用されません。</remarks>
                    Protected Overrides Function BeginDbTransaction(isolationLevel As IsolationLevel) As DbTransaction
                            Return Nothing
                    End Function
    
                    ''' <summary>
                    ''' データソース接続を開きます。
                    ''' </summary>
                    ''' <remarks>Csvデータプロバイダに対する使用されません。</remarks>
                    Public Overrides Sub Open()
                    End Sub
    
                    ''' <summary>
                    ''' データソースへの接続を閉じます。
                    ''' </summary>
                    Public Overrides Sub Close()
                            Dispose()
                    End Sub
    
                    Protected Overrides Function CreateDbCommand() As DbCommand
                            Return New CsvCommand(String.Empty)
                    End Function
    
                    ''' <summary>
                    '''<see cref="CsvCommand"/>により使用されたリソースを解放します。
                    ''' </summary>
                    Public Shadows Sub Dispose()
                            MyBase.Dispose(True)
                            GC.SuppressFinalize(Me)
                    End Sub
    
                    ''' <summary>
                    ''' <see cref="CsvConnection"/>のローカライズされた名前を取得します。
                    ''' </summary>
                    Public ReadOnly Property LocalizedName() As String
                            Get
                                    Return _localizedName
                            End Get
                    End Property
    
                    Public Overrides ReadOnly Property State() As ConnectionState
                            Get
                                    Return ConnectionState.Open
                            End Get
                    End Property
    
                    Public Overrides ReadOnly Property Database() As String
                            Get
                                    Return String.Empty
                            End Get
                    End Property
    
                    Public Overrides ReadOnly Property DataSource() As String
                            Get
                                    Throw New NotImplementedException()
                            End Get
                    End Property
    
                    Public Overrides ReadOnly Property ServerVersion() As String
                            Get
                                    Throw New NotImplementedException()
                            End Get
                    End Property
    
                    ''' <summary>
                    ''' この拡張機能の構成情報を指定します。
                    ''' </summary>
                    ''' <param name="configurationSettings">この設定の<see cref="NameValueCollection"/>。</param>
                    Public Sub SetConfiguration(configurationSettings As NameValueCollection)
                    End Sub
    
                    Public Shadows Function BeginTransaction(il As IsolationLevel) As IDbTransaction
                            'do nothing
                            Return Nothing
                    End Function
    
                    Public Overrides Sub ChangeDatabase(databaseName As String)
                            'do nothing
                    End Sub
            End Class
    End Namespace
    
    

    C#

    C#コード(デフォルトスタブと置換するには貼り付けます)
    コードのコピー
    using System;
    using System.Collections.Specialized;
    using System.Data;
    using System.Data.Common;
    
    namespace CustomDataProvider.CSVDataProvider
    {
            /// <summary>
            /// .NETフレームワークのCSVデータプロバイダの<see cref="DbConnection"/>を実装する方法を提供します。
            /// </summary>
            public sealed class CsvConnection : DbConnection
            {
                    private readonly string _localizedName;
    
                    /// <summary>
                    /// <see cref="CsvConnection"/>クラスの新しいインスタンスを作成します。
                    /// </summary>
                    public CsvConnection()
                    {
                            _localizedName = "Csv";
                    }
    
                    /// <summary>
                    /// <see cref="CsvConnection"/>クラスの新しいインスタンスを作成します。
                    /// </summary>
                    ///<param name="localizeName"><see cref="CsvConnection"/>のインスタンスのローカライズされた名前。</param>
                    public CsvConnection(string localizeName)
                    {
                            _localizedName = localizeName;
                    }
    
                    /// <summary>
                    /// データソースへの接続を開くために使用される文字列を取得または設定します。
                    /// </summary>
                    /// <remarks>Csvデータプロバイダに対する使用されません。</remarks>
                    public override string ConnectionString
                    {
                            get { return string.Empty; }
                            set { }
                    }
    
                    /// <summary>
                    /// 接続の実行を終了して、エラーを生成するまでの待機時間を取得します。
                    /// </summary>
                    /// <remarks>Csvデータプロバイダに対する使用されません。</remarks>
                    public override int ConnectionTimeout
                    {
                            get { throw new NotImplementedException(); }
                    }
    
                    /// <summary>
                    ///データソースのトランザクションを開始します。
                    /// </summary>
                    /// 新しいトランザクションを表すオブジェクト。
                    /// <remarks>Csvデータプロバイダに対する使用されません。</remarks>
                    protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
                    {
                            return null;
                    }
    
                    /// <summary>
                    /// データソース接続を開きます。
                    /// </summary>
                    /// <remarks>Csvデータプロバイダに対する使用されません。</remarks>
                    public override void Open()
                    {
                    }
    
                    /// <summary>
                    /// データソースへの接続を閉じます。
                    /// </summary>
                    public override void Close()
                    {
                            Dispose();
                    }
    
                    protected override DbCommand CreateDbCommand()
                    {
                            return new CsvCommand(string.Empty);
                    }
    
                    /// <summary>
                    ///<see cref="CsvCommand"/>により使用されたリソースを解放します。
                    /// </summary>
                    public new void Dispose()
                    {
                            Dispose(true);
                            GC.SuppressFinalize(this);
                    }
    
                    /// <summary>
                    /// <see cref="CsvConnection"/>のローカライズされた名前を取得します。
                    /// </summary>
                    public string LocalizedName
                    {
                            get { return _localizedName; }
                    }
    
                    public override ConnectionState State
                    {
                            get { return ConnectionState.Open; }
                    }
    
                    public override string Database
                    {
                            get
                            {
                                    return string.Empty;
                            }
                    }
    
                    public override string DataSource
                    {
                            get
                            {
                                    throw new NotImplementedException();
                            }
                    }
    
                    public override string ServerVersion
                    {
                            get
                            {
                                    throw new NotImplementedException();
                            }
                    }
    
                    /// <summary>
                    /// この拡張機能の構成情報を指定します。
                    /// </summary>
                    /// <param name="configurationSettings">この設定の<see cref="NameValueCollection"/>。</param>
                    public void SetConfiguration(NameValueCollection configurationSettings)
                    {
                    }
    
                    public new IDbTransaction BeginTransaction(IsolationLevel il)
                    {
                            //do nothing
                            return null;
                    }
    
                    public override void ChangeDatabase(string databaseName)
                    {
                            //do nothing
                    }
            }
    
    }
    
    
  11. CSVDataProviderフォルダを右クリックし、[追加]から[クラス]を選択し、ファイル名を「CsvDataProviderFactory」に変更します。デフォルトスタブを以下のコードに置き換えます。

    Visual Basic

    Visual Basicコード(クラスのデフォルトスタブと置き換えます)
    コードのコピー
    Imports System.Data.Common
    Namespace CSVDataProvider
            ''' <summary>
            ''' .NETフレームワークのCSVデータプロバイダの<see cref="DbProviderFactory"/>を実装する方法を提供します。
            ''' </summary>
            Public Class CsvDataProviderFactory
                    Inherits DbProviderFactory
    
                    ''' <summary>
                    ''' <see cref="CsvCommand"/>の新しいインスタンスを返します。
                    ''' </summary>
                    Public Overrides Function CreateCommand() As DbCommand
                            Return New CsvCommand()
                    End Function
    
                    ''' <summary>
                    ''' <see cref="CsvConnection"/>の新しいインスタンスを返します。
                    ''' </summary>
                    Public Overrides Function CreateConnection() As DbConnection
                            Return New CsvConnection()
                    End Function
            End Class
    End Namespace
    

    C#

    C#コード(クラスのデフォルトスタブと置き換えます)
    コードのコピー
    using System.Data.Common;
    
    namespace CustomDataProvider.CSVDataProvider
    {
            /// <summary>
            /// .NETフレームワークのCSVデータプロバイダの<see cref="DbProviderFactory"/>を実装する方法を提供します。
            /// </summary>
            public class CsvDataProviderFactory : DbProviderFactory
            {
                    /// <summary>
                    /// <see cref="CsvCommand"/>の新しいインスタンスを返します。
                    /// </summary>
                    public override DbCommand CreateCommand()
                    {
                            return new CsvCommand();
                    }
    
                    /// <summary>
                    /// <see cref="CsvConnection"/>の新しいインスタンスを返します。
                    /// </summary>
                    public override DbConnection CreateConnection()
                    {
                            return new CsvConnection();
                    }
            }
    }
    
    

クエリエディタにボタンを追加する

  1. CSVDataProviderフォルダを右クリックし、[追加]から[クラス]を選択し、ファイル名を「QueryEditor」に変更します。デフォルトスタブを以下のコードに置き換えます。

    Visual Basic

    Visual Basicコード(クラスのデフォールトスタブと置き換えます)
    コードのコピー
    Imports System
    Imports System.Collections.Generic
    Imports System.Drawing.Design
    Imports System.IO
    Imports System.Linq
    Imports System.Text
    Imports System.Text.RegularExpressions
    Imports System.Windows.Forms
    Imports System.Windows.Forms.Design
    
    Namespace CSVDataProvider
        Public NotInheritable Class QueryEditor
            Inherits UITypeEditor
            Dim path = ""
            Friend WithEvents btn As New Button()
            Public Overrides Function GetEditStyle(context As System.ComponentModel.ITypeDescriptorContext) As UITypeEditorEditStyle
                Return UITypeEditorEditStyle.DropDown
            End Function
            Public Overrides Function EditValue(context As System.ComponentModel.ITypeDescriptorContext, provider As System.IServiceProvider, value As Object) As Object
                Dim edSvc As IWindowsFormsEditorService = DirectCast(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
    
                btn.Text = "Select CSV File..."
                Dim pdg = btn.Padding
                pdg.Bottom += 2
                btn.Padding = pdg
                edSvc.DropDownControl(btn)
                If String.IsNullOrEmpty(path) Then
                    Return String.Empty
                End If
                If Not File.Exists(path) Then
                    Return String.Empty
                End If
                            Return GetCSVQuery(path)
    
                    End Function
    
            Private Sub btn_Click(sender As System.Object, e As System.EventArgs) Handles btn.Click
                Using openDlg = New OpenFileDialog()
                    openDlg.Filter = "CSV Files (*.csv)|*.csv|All Files (*.*)|*.*"
                    If openDlg.ShowDialog() <> DialogResult.OK Then
                        path = ""
                    Else
                        path = openDlg.FileName
                    End If
    
                End Using
            End Sub
    
                    Private Shared Function GetCSVQuery(ByVal csvFileName As String) As String
                            Dim sr As StreamReader = Nothing
                            Try
                                    sr = New StreamReader(csvFileName)
                                    Dim ret As String = String.Empty
                                    Dim currentLine As String
                                    Dim line As Integer = 0
    
                                    currentLine = sr.ReadLine()
                                    While (currentLine) IsNot Nothing
                                            If (line).Equals(0) Then
                                                    ret += ProcessColumnsDefinition(currentLine) + vbCr & vbLf
                                            Else
                                                    ret += currentLine + vbCr & vbLf
                                            End If
                                            line = line + 1
                                            currentLine = sr.ReadLine()
                                    End While
                                    Return ret
                            Catch generatedExceptionName As IOException
                                    Return String.Empty
                            Finally
                                    If Not (sr) Is Nothing Then
                                            sr.Close()
                                    End If
                            End Try
                    End Function
    
                    Private Shared Function ProcessColumnsDefinition(ByVal line As String) As String
                            Const ColumnWithDataTypeRegex As String = "[""]?\w+[\""]?\(.+\)"
                            Dim columns As String() = line.Split(New String() {","}, StringSplitOptions.None)
                            Dim ret As String = Nothing
                            For Each column As String In columns
                                    If Not String.IsNullOrEmpty(ret) Then
                                            ret += ","
                                    End If
                                    If Not Regex.Match(column, ColumnWithDataTypeRegex).Success Then
                                            ret += column + "(string)"
                                    Else
                                            ret += column
                                    End If
                            Next
                            Return ret
                    End Function
            End Class
    End Namespace
    

    C#

    C#コード(デフォールトスタブと置換するには貼り付けます)
    コードのコピー
    using System;
    using System.Collections.Generic;
    using System.Drawing.Design;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;
    
    namespace CustomDataProvider.CSVDataProvider
    {
        public sealed class QueryEditor : UITypeEditor
        {
            public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
            {
                return UITypeEditorEditStyle.DropDown;
            }
    
            public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)
            {
                IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
                var path = "";
                var btn = new Button();
                btn.Text = "Select CSV File...";
                var pdg = btn.Padding;
                pdg.Bottom += 2;
                btn.Padding = pdg;
    
                btn.Click += delegate
                {
                    using (var openDlg = new OpenFileDialog())
                    {
                        openDlg.Filter = "CSV Files (*.csv)|*.csv|All Files (*.*)|*.*";
                        if (openDlg.ShowDialog() != DialogResult.OK)
                            path = "";
                        else
                            path = openDlg.FileName;
                    }
                };
    
    
                edSvc.DropDownControl(btn);
    
                if (string.IsNullOrEmpty(path)) return string.Empty;
                if (!File.Exists(path)) return string.Empty;
    
                return GetCSVQuery(path);
            }
    
            /// <summary>
            /// 指定したファイルの内容を読み込み、CSVデータプロバイダのクエリ文字列を作成します。
            /// </summary>
            /// <param name="csvFileName">CSVファイルの完全なパス。</param>
            /// <returns>CSVデータプロバイダのクエリ文字列。</returns>
            /// <remarks>
            /// この方法は、ファイルの行を1つずつ読み込み、クエリ文字列に追加します。
            /// CSVのクエリ文字列の先頭行には、列名と列のデータ型があるため、
            ///特有の処理を実行します。
            /// </remarks>
            private static string GetCSVQuery(string csvFileName)
            {
                StreamReader sr = null;
                try
                {
                    sr = new StreamReader(csvFileName);
                    string ret = string.Empty;
                    string currentLine;
                    int line = 0;
                    while ((currentLine = sr.ReadLine()) != null)
                    {
                        if (line == 0)
                            ret += ProcessColumnsDefinition(currentLine) + "\r\n";
                        else
                            ret += currentLine + "\r\n";
                        line++;
                    }
                    return ret;
                }
                catch (IOException)
                {
                    return string.Empty;
                }
                finally
                {
                    if (sr != null)
                        sr.Close();
                }
            }
    
            /// <summary>
            ///指定した文字列からCSVデータの列の定義を読み込み、必要に応じて調整します。
            /// </summary>
            /// <param name="line">CSVデータの列の定義を含む文字列。</param>
            /// <returns>データ型の定義を含むCSVデータ列の定義。</returns>
            private static string ProcessColumnsDefinition(string line)
            {
                const string ColumnWithDataTypeRegex = @"[""]?\w+[\""]?\(.+\)";
                string[] columns = line.Split(new string[] { "," }, StringSplitOptions.None);
                string ret = null;
                foreach (string column in columns)
                {
                    if (!string.IsNullOrEmpty(ret))
                        ret += ",";
                    if (!Regex.Match(column, ColumnWithDataTypeRegex).Success)
                    {
                        ret += column + "(string)";
                    }
                    else
                    {
                        ret += column;
                    }
                }
                return ret;
            }
    
        }
    }
    
  2. CustomDataProviderDemoプロジェクトを右クリックし、[参照の追加]を選択します。[参照の追加]ダイアログでは[プロジェクト]タブから、CustomDataProviderを選択し、OKをクリックします。
  3. プロジェクトを実行し、RichTextBoxに表示されている手順に沿って、カスタムデータプロバイダを設定します。