web-dev-qa-db-ja.com

ここで「拡張メソッドを動的にディスパッチできない」原因は何ですか?

コンパイルエラー

「System.Data.SqlClient.SqlConnection」には「Query」という名前の該当するメソッドはありませんが、その名前の拡張メソッドがあるようです。拡張メソッドは動的にディスパッチできません。動的引数をキャストするか、拡張メソッド構文なしで拡張メソッドを呼び出すことを検討してください。

これで、問題を回避する方法がわかりましたが、エラー自体をよりよく理解しようとしています。 Dapperを活用するために構築しているクラスがあります。最後に、私たちのタイプのデータアクセスをより合理化するために、さらにいくつかのカスタム機能を提供します。特にトレースなどの構築。ただし、現時点では、次のように簡単です。

public class Connection : IDisposable
{
    private SqlConnection _connection;

    public Connection()
    {
        var connectionString = Convert.ToString(ConfigurationManager.ConnectionStrings["ConnectionString"]);
        _connection = new SqlConnection(connectionString);
        _connection.Open();
    }

    public void Dispose()
    {
        _connection.Close();
        _connection.Dispose();
    }

    public IEnumerable<dynamic> Query(string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
    {
        // this one works fine, without compile error, so I understand how to
        // workaround the error
        return Dapper.SqlMapper.Query(_connection, sql, param, transaction, buffered, commandTimeout, commandType);
    }

    public IEnumerable<T> Query<T>(string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
    {
        // this one is failing with the error
        return (IEnumerable<T>)_connection.Query(sql, param, transaction, buffered, commandTimeout, commandType);
    }
}

しかし、興味深いことに、私が単に次のようなステートメントを発行した場合:

_connection.Query("SELECT * FROM SomeTable");

それはうまくコンパイルされます。

それで、誰かが私がそれらの他のメソッドの中で同じ過負荷を利用することがそのエラーで失敗する理由を理解するのを手伝ってくれるでしょうか?

32
Mike Perrenoud

それで、誰かが私がそれらの他のメソッドの中で同じ過負荷を利用することがそのエラーで失敗する理由を理解するのを手伝ってくれるでしょうか?

引数の1つとして動的な値(param)を使用しているためです。つまり、動的ディスパッチが使用されますが、拡張メソッドでは動的ディスパッチはサポートされていません。

ただし、解決策は簡単です。静的メソッドを直接呼び出すだけです。

return SqlMapper.Query(_connection, sql, param, transaction,
                       buffered, commandTimeout, commandType);

(もちろん、実際にparamdynamicタイプである必要があることを前提としています...もちろん、コメントに記載されているように、単にobjectに変更することもできます。 )

39
Jon Skeet

同じ問題に対する別の解決策は、動的値に型キャストを適用することです。

私は同じコンパイルエラーに遭遇しました:

Url.Asset( "path/" + article.logo );

これを行うことで解決しました:

Url.Asset( "path/" + (string) article.logo );

注:この場合、動的な値は文字列であることがよく知られています。存在する文字列の連結によって補強された事実。

1
starlocke