他の誰かがこの同じ問題に遭遇したかどうか知りたいです...私はプロジェクトのORMでDapperを使用しており、IDbConnection
コードを簡素化するためにインターフェースから独自の拡張メソッドをいくつか作成していました。 (私が見つけたのは)不可解なエラーです。
私が行ったプロセスを説明します。
DbExtensions
まず、次のような名前の静的クラスでプロジェクトに拡張メソッドを追加しました。
using System.Collections.Generic;
using System.Data;
using System.Linq;
public static class DbExtensions
{
public static T Scalar<T>(
this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
{
var ret = cnn.Query<T>(sql, param as object, transaction, buffered, commandTimeout, commandType).First();
return ret;
}
}
これにより、次の説明でコンパイル エラーが発生します。
'System.Data.IDbConnection' 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.
これは問題ありません。エラーは、修正方法も教えてくれるので、実際にはかなり役に立ちます。だから私は試してみます:
using System.Collections.Generic;
using System.Data;
using System.Linq;
public static class DbExtensions
{
public static T Scalar<T>(
this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
{
var ret = SqlMapper.Query<T>(cnn, sql, param, transaction, buffered, commandTimeout, commandType).First();
return ret;
}
}
そしてそれは正しくコンパイルされます。しかし、何か奇妙なことが起こっています。Visual Studio で、 の戻り値を取り、SqlMapper.Query<T>
それを操作しようIEnumerable<T>
とすると、Visual Studio は、 経由で継承されたものを除いて、インテリセンス プロパティを提供しませんobject
。
インテリセンスでは理解できないことをしているだけだと思って、実際にコードを実行しようとするまで、陽気な道を進みます。
実行しようとすると、呼び出している場所で.First()
次のエラーが発生します。
'System.Collections.Generic.List<MyNameSpace.MyClass>' does not contain a definition for 'First'
さて、このエラー、面白いと思いました...しばらく頭を悩ませた後、最初の引数が動的型付けについて不平を言っていることに気付きました...
IEnumerable<T>
このエラーが発生しているのは、DLR で実行されているときにクエリが返されることをコンパイラが認識できないため、コンパイラがジェネリック テンプレートをビルドできないためだと思い ますか? どなたか詳しい方に説明していただきたいです。私は本質的にそれを修正する2つの方法を見つけました:
dynamic
パラメータをにキャストするobject
- 戻り値を
IEnumerable<T>
using System.Collections.Generic;
using System.Data;
using System.Linq;
public static class DbExtensions
{
public static T Scalar<T>(
this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
{
var ret = SqlMapper.Query<T>(cnn, sql, param as object, transaction, buffered, commandTimeout, commandType).First();
return ret;
}
}
using System.Collections.Generic;
using System.Data;
using System.Linq;
public static class DbExtensions
{
public static T Scalar2<T>(
this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
{
var ret = ((IEnumerable<T>)SqlMapper.Query<T>(cnn, sql, param, transaction, commandTimeout, commandType)).First();
return ret;
}
}
要約すれば:
私は DLR のクワークに取り組むのが初めてで、動的 + ジェネリックをいじる際に留意すべきいくつかの注意点があるようです...?
これ自体が質問ではないことはわかっていますが、実際にこれを書き始めたとき、何が起こっているのかわかりませんでしたが、その過程でそれを理解しました! 私はそれが同じような問題を抱えている他の誰かを助けるかもしれないと思った...