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

.net c# compiler-errors dapper extension-methods

質問

コンパイルエラー

'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");

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

だから、他のメソッドの中で同じオーバーロードを利用することが、そのエラーで失敗するのをなぜ理解するのを助けることができますか?

受け入れられた回答

だから、他のメソッドの中で同じオーバーロードを利用することが、そのエラーで失敗するのをなぜ理解するのを助けることができますか?

正確には、動的値( param )を引数の1つとして使用しているからです。これは動的ディスパッチを使用することを意味しますが、拡張メソッドでは動的ディスパッチはサポートされていません。

解決方法は簡単ですが、静的メソッドを直接呼び出してください:

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

(これは、あなたが実際にdynamic型のparamを必要としていると仮定しています。コメントに記載されているように、 object変更するだけでうまくいくかもしれません)。


人気のある回答

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

同じコンパイルエラーが発生しました:

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

どちらが解決したのか:

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

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



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow