私はMedusaを更新して、現在はList<DbParameter>
を使用しているどこでも装飾されたPOCOを使用できるようにしようとしています。私が実行している問題は、間違ったオーバーロードが呼び出されているということです。ここで私が見ているかの簡単な例です。この場合はgenericパラメータを渡すと、間違ったオーバーロードが発生する
void Run()
{
CallDoSomething<Program>("Hello World", new object());
CallDoSomething<Program>("Hello World2", new List<int>());
}
// `DoSomething<T>` represents the functions that do the heavy lifting
public T DoSomething<T>(string someString, List<int> ints) where T : class
{
Console.WriteLine("List<int>: {0}", someString);
return default(T);
}
public T DoSomething<T>(string someString, object ints) where T : class
{
Console.WriteLine("object: {0}", someString);
// In my real implementation, this turns the object to a typed List<T>
// and passes it to the previous overload.
return default(T);
}
// We're trying to refactor the code in this method to reduce code duplication in
// the `CallDoSomething<T>` methods that will actually be called by the end user
internal T CallDoSomething<T, U>(string someString, U ints) where T : class
{
// Do a bunch of stuff here that would otherwise be duplicated by the `CallDoSomething<T>` methods
return DoSomething<T>(someString, ints);
}
public T CallDoSomething<T>(string someString, List<int> ints) where T : class
{
return CallDoSomething<T, List<int>>(someString, ints);
}
public T CallDoSomething<T>(string someString, object ints) where T : class
{
return CallDoSomething<T, object>(someString, ints);
}
、出力結果は次のとおりです。
object: Hello World
object: Hello World2
私はそれがあることを期待していた中:
object: Hello World
List<int>: HelloWorld2
両方ともオブジェクトであるので、両方のケースがobject
パラメータを取るオーバーロードに向けられていたことは意味があります。私はこれが起こっていると思う(私が知っているところから)ジェネリックスとオーバーロードの解決は、実行時ではなくコンパイル時に処理されます。
私に来た最初の選択肢はReflectionを使用してCallDoSomething<T, U>
で呼び出しを動的に呼び出すことでしたが、それはあまりにも汚いと感じました。代わりに、私が思いついた解決策は、デリケートをCallDoSomething<T, U>
に渡すことです。これはうまくいくようです。ここでは次のようになります。
void Run()
{
CallDoSomething<Program>("Hello World", new object());
CallDoSomething<Program>("Hello World2", new List<int>());
}
public T DoSomething<T>(string someString, List<int> ints) where T : class
{
Console.WriteLine("List<int>: {0}", someString);
return default(T);
}
public T DoSomething<T>(string someString, object ints) where T : class
{
Console.WriteLine("object: {0}", someString);
return default(T);
}
internal delegate T DoSomethingDelegate<T, U>(string someString, U ints) where T : class;
internal T CallDoSomething<T, U>(string someString, U ints, DoSomethingDelegate<T, U> doSomething) where T : class
{
// Do a bunch of stuff here that would otherwise be duplicated by the `CallDoSomething<T>` methods
return doSomething(someString, ints);
}
public T CallDoSomething<T>(string someString, List<int> ints) where T : class
{
return CallDoSomething<T, List<int>>(someString, ints, DoSomething<T>);
}
public T CallDoSomething<T>(string someString, object ints) where T : class
{
return CallDoSomething<T, object>(someString, ints, DoSomething<T>);
}
これが動作しているようですし、それがコードの重複を大量に削除されますが、それはコードがかなり複雑になります。この問題にアプローチするにはよりよい方法がありますか?
私は.NET 4に入っていますので、「動的」は私の心を邪魔しましたが、 'ints'はすでに一般的なので大きな違いはないと思いました。しかしそれは意味をなさない。デザインを簡素化するためのアドバイスはありますか? –
@ M.Babcock:ジェネリックとダイナミックは非常に異なります。ジェネリックスは、*コンパイル時により多くの型情報を提供することです。動的なのは、*実行時により多くの型情報を使用することです。デザインを簡素化するために、より多くの文脈を知らなくては言い難いです。 –
ご協力ありがとうございます。私はたぶん、代理人に固執して.NET 4の外部での使用を許可します。デリゲートのソリューションが機能しているように見えますが、このような理由で*ない*を知っていますか? –