2010-12-08 11 views
1

私はcastle windsorのサブ依存関係リゾルバを作成しています。リゾルバは汎用インタフェースを実装するオブジェクトを返します。汎用パラメータは実行時に解決され、ファクトリは正しい実装を返すために使用されます。ファクトリメソッドのMethodInfoを取得するために文字列を使用したくありません。次のように動作しますが、ファクトリの作成メソッドを解決するには、GetMethodNameとその使用方法を見てください。これは虐待があるかどうリフレクションを使用して文字列名を使用せずに一般的なMethodInfoを取得し、実行時に汎用パラメータが解決される

public class FooFactoryResolver : ISubDependencyResolver 
{ 
    private static string factoryMethodName; 
    private readonly IWindsorContainer container; 

    public FooFactoryResolver (IWindsorContainer container) 
    { 
     this.container = container; 
    } 

    private static string GetMethodName() 
    { 
     if (factoryMethodName == null) 
     { 
      IFooFactory fooFactory = null; 

      Expression<Func<IFoo<object, object>>> expression = 
       () => fooFactory .CreateFoo<object, object>(); 

      factoryMethodName = ((MethodCallExpression)expression.Body). 
       Method.Name; 
     } 
     return factoryMethodName; 
    } 

    public object Resolve(CreationContext context, 
     ISubDependencyResolver contextHandlerResolver, 
     Castle.Core.ComponentModel model, DependencyModel dependency) 
    { 
     return 
      TryToResolveDirectly(dependency) ?? 
      TryToResolveUsingFactories(dependency) ?? 
      ComponentNotFound(dependency); 
    } 

    private static object ComponentNotFound(DependencyModel dependency) 
    { 
     throw new ComponentNotFoundException(dependency.TargetType); 
    } 

    private object TryToResolveUsingFactories(DependencyModel dependency) 
    { 
     var fooFactories = this.container.ResolveAll<IFooFactory>(); 

     Type[] genericTypes = dependency.TargetItemType. 
      GetGenericArguments().ToArray(); 

     return (from fooFactory in fooFactories 
       where fooFactory.CanCreate(genericTypes[0], 
        genericTypes[1]) 
       let factoryMethod = fooFactory.GetType(). 
        GetMethod(GetMethodName()) 
       select factoryMethod.MakeGenericMethod( 
        genericTypes.ToArray()). 
        Invoke(fooFactory, new object[0])). 
        FirstOrDefault(); 
    } 

    private object TryToResolveDirectly(DependencyModel dependency) 
    { 
     return this.container.Kernel.HasComponent(dependency.TargetType) ? 
      this.container.Resolve(dependency.TargetType) : null; 
    } 

    public bool CanResolve(CreationContext context, 
     ISubDependencyResolver contextHandlerResolver, 
     Castle.Core.ComponentModel model, DependencyModel dependency) 
    { 
     return dependency.TargetType.GetGenericTypeDefinition() == 
      typeof(IFoo<,>); 
    } 
} 

public interface IFoo<T1, T2> { } 

public interface IFooFactory 
{ 
    IFoo<T1, T2> CreateFoo<T1, T2>(); 
    bool CanCreate(Type a, Type b); 
} 

は私はわからないが、それは私はちょうど私が何かを明らかに行方不明だと感じ、仕事を取得します。私は、MethodInfoの一般的なパラメータをMethodCallExpressionから変更する方法や、MethodInfoからそれを 'Parent'に戻し、必要な型を使用してMakeGenericMethodを呼び出す方法があることを期待していました。

+2

Reflection APIを使用しているオープンジェネリックをサポートしています。それは悲しい事実です。それがうまくいくなら、それをそのまま残して、もっと面白い仕事に移りなさい。私はこれにあまりにも多くの時間を費やすことはありません。 –

+0

@ KrzysztofあなたがOCDでないなら、それはいいです:)。ウェイクアップコールに感謝します。 – Bronumski

答えて

0

CreateFooメソッドに適用するカスタム属性を作成し、Reflectionを使用してインターフェイスの種類の属性を探します(常に見つかります)。これによりExpressionを作成する必要がなくなり、属性を探すことができます。 MethodInfoが見つかったら、そこから名前を取得できます。

IFooFactory.CreateFoo<T1, T2>()の閉じた型宣言を取得する必要はありません。単に名前を取得しようとしていますが、タイプがのメソッド宣言を閉じると、名前が変更されません

関連する問題