3

私は昨日からこの方法を機能させようとしていて、髪を引っ張っています-

基本的に、データベースから記事を取得するメソッドがあります。以下はメソッドコードです。

public static IEnumerable<Article> RetrieveTopTenArticles()
{
    using(var dbConn = new SqlConnection(Settings.Instance.DbConnectionString))
    {
        const String query = "SELECT TOP 10 Title, Content FROM Article";
        Func<SqlDataReader, Article> operation = reader => reader.ToArticle();
        return dbConn.SqlRetrieveMultiple(query, operation);
    }
}

そして、別の「拡張機能」クラスで-

public static IEnumerable<T> SqlRetrieveMultiple<T>(this SqlConnection sqlConnection, String query, Func<SqlDataReader, T> operation, params SqlParameter[] parameters)
{
    sqlConnection.Open();
    using (var command = new SqlCommand(query, sqlConnection))
    {
        if (parameters.Length > 0)
        {
            command.Parameters.AddRange(parameters);
        }
        using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                yield return operation.Invoke(reader);
            }
        }
    }
}

ご覧のとおり、SQL select ステートメントを実行し、結果を反復処理して操作を呼び出し、各 SqlDataReader 行を Article タイプに変換する拡張メソッドがあります (これも拡張メソッドで実行されます)。過去にこれとまったく同じ拡張方法を問題なく使用したと思います。

これをデバッグすると、dbConn.SqlRetrieveMultiple(query, operation); に到達します。F11 キーを押してステップインすると、行を完全にステップオーバーします。ネストされたブラケットの終わりのチェーンをたどり続け、最終的に sqlConnection.Open() で例外が発生します。

私が得る例外は次のとおりです。

ConnectionString プロパティが初期化されていません。

Func デリゲートを削除すると、関数が問題なく実行されることがわかりました。同じクラス内の通常のプライベート静的メソッドに配置すると同じ動作が得られるため、これは拡張メソッドまたは SqlConnection とは無関係/愚かなものでなければならないと感じています。sqlConnection.Open(); で .NET フレームワーク ソース ステップをオンにすると、行、それは .NET フレームワークの ctor メソッドにジャンプします... 要求があれば、さらにコードを投稿できますが、必要なものはすべて揃っていると思います。アイデアがあれば教えてください。

4

2 に答える 2

4

列挙するのではなく、反復子メソッドの結果を返しています。イテレータ メソッドは遅延実行を使用します。その結果、使用する接続が破棄されるまで、実際には何も実行されません。そのため、メソッドを「ステップオーバー」しただけであり、後で任意の時点で失敗しました。

この問題は 2 つの方法で解決できます。ToArray のようなメソッドを使用して、事前にすべての結果を取得して返し、廃棄が発生する前にアイテムを熱心に取得します。

return dbConn.SqlRetrieveMultiple(query, operation).ToArray();

または、外側のメソッドを反復子メソッドにすることで、アイテムが遅延取得されるまで破棄を遅らせることができます。

using(var dbConn = new SqlConnection(Settings.Instance.DbConnectionString))
{
    const String query = "SELECT TOP 10 Title, Content FROM Article";
    Func<SqlDataReader, Article> operation = reader => reader.ToArticle();
    foreach (var e in dbConn.SqlRetrieveMultiple(query, operation))
        yield return e;
}

ただし、ユーザーがこの遅延バージョンを 2 回繰り返すと、2 つの接続を開くことになることに注意してください。それはあなたが望むものかもしれませんし、そうでないかもしれません。

于 2012-12-07T04:08:22.953 に答える
1

与えられた例外は、接続文字列に何か問題があることを意味します。投稿してください。


また、私はあなたの機能をこのように使用します:

while (reader.Read())
{
    yield return operation(reader);
}
于 2012-12-07T04:04:34.300 に答える