次のようなサービス インターフェイスがあるとします。
public interface IFooService
{
FooResponse Foo(FooRequest request);
}
このようなサービスでメソッドを呼び出す際に、いくつかの分野横断的な問題を解決したいと考えています。たとえば、統一された要求ログ、パフォーマンス ログ、およびエラー処理が必要です。私のアプローチは、メソッドの呼び出しとその周りで他のことを処理するメソッドを持つ共通の基本「リポジトリ」クラスを持つInvoke
ことです。私の基本クラスは次のようになります。
public class RepositoryBase<TService>
{
private Func<TService> serviceFactory;
public RepositoryBase(Func<TService> serviceFactory)
{
this.serviceFactory = serviceFactory;
}
public TResponse Invoke<TRequest, TResponse>(
Func<TService, Func<TRequest, TResponse>> methodExpr,
TRequest request)
{
// Do cross-cutting code
var service = this.serviceFactory();
var method = methodExpr(service);
return method(request);
}
}
これはうまくいきます。しかし、コードをよりクリーンにするという私の目標は、型推論が期待どおりに機能しないという事実によって妨げられています。たとえば、次のようなメソッドを記述したとします。
public class FooRepository : BaseRepository<IFooService>
{
// ...
public BarResponse CallFoo(...)
{
FooRequest request = ...;
var response = this.Invoke(svc => svc.Foo, request);
return response;
}
}
次のコンパイル エラーが発生します。
メソッド ... の型引数は、使用法から推測できません。型引数を明示的に指定してみてください。
明らかに、呼び出しを次のように変更することで修正できます。
var response = this.Invoke<FooRequest, FooResponse>(svc => svc.Foo, request);
しかし、これは避けたいと思います。型推論を利用できるようにコードを作り直す方法はありますか?
編集:
また、以前のアプローチでは拡張メソッドを使用していたことにも言及する必要があります。これの型推論は機能しました:
public static class ServiceExtensions
{
public static TResponse Invoke<TRequest, TResponse>(
this IService service,
Func<TRequest, TResponse> method,
TRequest request)
{
// Do other stuff
return method(request);
}
}
public class Foo
{
public void SomeMethod()
{
IService svc = ...;
FooRequest request = ...;
svc.Invoke(svc.Foo, request);
}
}