What causes “extension methods cannot be dynamical

2019-01-09 15:03发布

问题:

Compile Error

'System.Data.SqlClient.SqlConnection' has no applicable method named 'Query' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.

Now, I know how to work around the problem, but I'm trying to get a better understanding of the error itself. I have class that I'm building to leverage Dapper. In the end I'm going to provide some more custom functionality to make our type of data access a lot more streamlined. In particular building in tracing and stuff. However, right now it's as simple as this:

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);
    }
}

but interestingly enough, if I were to simply issue a statement like this:

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

it compiles just fine.

So, can somebody please help me understand why leveraging the same overload inside of those other methods is failing with that error?

回答1:

So, can somebody please help me understand why leveraging the same overload inside of those other methods is failing with that error?

Precisely because you're using a dynamic value (param) as one of the arguments. That means it will use dynamic dispatch... but dynamic dispatch isn't supported for extension methods.

The solution is simple though: just call the static method directly:

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

(That's assuming you really need param to be of type dynamic, of course... as noted in comments, you may well be fine to just change it to object.)



回答2:

Another solution to the same issue is to apply type casting to the dynamic value.

I encountered the same compile error with:

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

Which was resolved by doing:

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

Note: the dynamic value is well-known to be a string, in this case; a fact reinforced by the string concatenation that is present.