0

すべてのデータベースアクションを担当するクラスがあります。通常、このクラスはストアドプロシージャを呼び出します。

クラスに2つのデリゲートを作成しました。1つは肯定応答(たとえば、サーバーがOKを返しました)を担当し、もう1つはすべてのエラー処理を担当します。

public delegate void Part1_Callback(string message);
public delegate void Part2_Callback(DataTable dt);
public delegate void Part3_Callback(DataTable dt, int x, int y);
public delegate void ErrorHandler(string message);

前の質問で示したように、すべてのメソッドを非同期で呼び出します:シングルトンとデリゲート内のC#非同期SQL

デリゲートが別のタイプのデータを返す必要がある場合、問題が発生します。

たとえば、私の最初のメソッドは、、String2番目のa DataTable、3番目のaDataTableと2を返しますints

今のところ、すべてのメソッドについて、パラメーターを保持するクラスを作成する必要があります。

public class Part1_CommandAndCallback
{
    public SqlCommand Sql;
    public Part1_Callback Callback;
    public ErrorHandler Error;
}

public class Part2_CommandAndCallback
{
    public SqlCommand Sql;
    public Part2_Callback Callback;
    public ErrorHandler Error;
}

public class Part3_CommandAndCallback
{
    public SqlCommand Sql;
    public Part3_Callback Callback;
    public ErrorHandler Error;
}

応答用に1つのデリゲート、パラメーター用に1つのクラスを持つことができるように、1つのジェネリックデリゲートを作成することは可能ですか?

このようにして、コードをより簡単に制御できるようになります。

codeprojectに関する記事を見つけました:http://www.codeproject.com/Articles/192027/Delegates-101-Part-III-Generic-Delegatesしかし、私の場合、これを使用する方法がわかりません:/

代理人を次のように宣言する必要があります。

delegate void MyDelegate (params object[] params);

また:

public delegate void MyDelegate2<T>(T param1);

ただし、この方法では1つのパラメーターしか渡すことができず、3つのパラメーターに同じデリゲートを使用することはできません。

どちらの解決策が良いですか?異なるタイプの1〜3個のパラメーターを受け取ることができる1つのジェネリックデリゲートが必要です。

これはできますか?

編集:

私は自分のシナリオを見せようとします:

私のメインフォームクラスでは、次のようにDBクラスを呼び出しています。

    private void form1_Enter(object sender, EventArgs e)
    {
        showStatus("Loading statistics...");
        DB.Instance.Part1(part1_ok,ErrorHandler);
        DB.Instance.Part2(part2_ok, ErrorHandler);
    }
    private void ErrorHandler(string msg)
    {
        hideStatus();
        //viewStack1.InvokeIfRequired(c => { c.moveToFirst(); });
        MessageBox.Show(msg, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }

    private void part1_ok(string msg)
    {
        MessageBox.Show(msg);

    }

    private void part2_ok(DataTable dt)
    {
        dataGridView1.InvokeIfRequired(c =>
        {
            c.DataSource = dt;
        });
    }

私のDBクラスは次のようになります。

public delegate void Part1_Callback(string message);
public delegate void Part2_Callback(DataTable dt);
public delegate void Part3_Callback(DataTable dt, int x, int y);
public delegate void ErrorHandler(string message);

public class Part1_CommandAndCallback
{
    public SqlCommand Sql;
    public Part1_Callback Callback;
    public ErrorHandler Error;
}

public class Part2_CommandAndCallback
{
    public SqlCommand Sql;
    public Part2_Callback Callback;
    public ErrorHandler Error;
}

public class Part3_CommandAndCallback
{
    public SqlCommand Sql;
    public Part3_Callback Callback;
    public ErrorHandler Error;
}

class DB : SingletonBase<DB>
{

    public static readonly string SqlConnectionString  = @"Data Source=MyDB;Initial Catalog=Stats;Integrated Security=True;Asynchronous Processing=true;";

    private DB()
    {
    }

    public void Part1(Part1_Callback callback, ErrorHandler error)
    {
        SqlConnection conn = new SqlConnection(SqlConnectionString);
        SqlCommand cmd = conn.CreateCommand();
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.CommandText = "Part1";

        try
        {
            conn.Open();
        }
        catch (Exception ex)
        {
            error(ex.ToString());
            return;
        }

        Part1_CommandAndCallback ar = new Part1_CommandAndCallback() { Callback = callback, Error = error, Sql = cmd };
        IAsyncResult result = cmd.BeginExecuteReader(new AsyncCallback(Part1_Handler), ar, CommandBehavior.CloseConnection);
    }

    private void Part1_Handler(IAsyncResult result)
    {
        string stats = string.Empty;
        Part1_CommandAndCallback ar = (Part1_CommandAndCallback)result.AsyncState;
        SqlDataReader dr;

        if (result.IsCompleted)
        {
            dr = ar.Sql.EndExecuteReader(result);
        }
        else
            dr = null;

        while (dr.Read())
        {
            stats += dr[0].ToString() + Environment.NewLine;
        }
        dr.NextResult();

        while (dr.Read())//problem is here
        {
            stats += dr[0].ToString() + " - " + dr[1].ToString() +Environment.NewLine;
        }
        dr.Close();
        ar.Callback(stats);
    }

    public void Part2(Part2_Callback callback, ErrorHandler error)
    {
        SqlConnection conn = new SqlConnection(SqlConnectionString);
        SqlCommand cmd = conn.CreateCommand();
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.CommandText = "Part2";

        try
        {
            conn.Open();
        }
        catch (Exception ex)
        {
            error(ex.ToString());
            return;
        }

        Part2_CommandAndCallback ar = new Part2_CommandAndCallback() { Callback = callback, Error = error, Sql = cmd };
        IAsyncResult result = cmd.BeginExecuteReader(new AsyncCallback(Part2_Handler), ar, CommandBehavior.CloseConnection);
    }

    private void Part2_Handler(IAsyncResult result)
    {
        DataTable dt = new DataTable();
        Part2_CommandAndCallback ar = (Part2_CommandAndCallback)result.AsyncState;
        SqlDataReader dr;

        if (result.IsCompleted)
        {
            dr = ar.Sql.EndExecuteReader(result);
        }
        else
            dr = null;

        dt.Load(dr);
        dr.Close();
        ar.Callback(dt);
    }
}

私のアイデアは、シングルトンDBコントローラーをさまざまな形で同時に使用することでした。したがって、最初の形式では自動更新されるいくつかの統計が表示され、2番目の形式では、ボタンをクリックすると更新できるいくつかの異なる統計が表示されます。

4

2 に答える 2

2

組み込みのデリゲートを使用すると思いますが、

Action<T>
Action<T, T>

ここを参照してください:

http://msdn.microsoft.com/en-us/library/018hxwa8.aspx

于 2012-09-17T09:44:37.363 に答える
1

必要なのはジェネリックCommandAndCallbackクラスを作成することのようです。

public class CommandAndCallback<TCallback>
{
    public SqlCommand Sql;
    public TCallback Callback;
    public ErrorHandler Error;
}

また、たとえば、以前はを使用していましたが、各パーツのデリゲートタイプを作成したくない場合は、をPart3_CommandAndCallback使用するCommandAndCallback<Part3_Callback>か、さらにはを使用します。CommandAndCallback<Action<DataTable, int, int>>

また、パブリックフィールドは一般的に推奨されていないため、autopropertiesに変更することを検討してください。

public class CommandAndCallback<TCallback>
{
    public SqlCommand Sql { get; set; }
    public TCallback Callback { get; set; }
    public ErrorHandler Error { get; set; }
}
于 2012-09-17T09:45:23.787 に答える