2009-12-11 3 views
2

일반적인 오버로드 된 메서드는 어떻게 찾을 수 있습니까? 예를 들어, Queryable의이일반적인 오버로드 된 메서드 찾기 및 호출

public static IQueryable<TResult> Select<TSource , TResult> (this IQueryable<TSource> source , Expression<Func<TSource , int , TResult>> selector); 

내가 기존 솔루션을 검토 한 결과, 그들은 하나없는 일반적인 충분히있어 (메소드의 매개 변수를 기반으로하는 등, 계산), 필요 (내가 가진 것보다 더 많은 매개 변수를 필요

정의 클래스 유형은 Type type이고 메소드 이름은 string name이며 매개 변수 유형의 배열은 없습니다 (일반 유형 정의 또는 인수). 일반적인 정의) - Type[] types.

지금까지 비교하여 제가 특정 유형의 잠재 방법의 .GetGenericArguments()의 각을지도해야 할 것 같다 (제네릭 형식 트리를?) 방법의 .GetParameters().Select (p=>p.ParameterType)types 배열에서 해당 항목의, 따라서의 일반적인 인수를 추론 방법, 그래서 난 .MakeGenericMethod 수 있습니다.

이 작업은 너무 복잡해 보이기 때문에 모든 것을 지나치게 생각하고 있습니다.

어떤 도움이 필요합니까?

답변

1

좋아, 그래서 난 그냥 본질적으로 수동 유형 유추입니다 코딩, 그리고 내가 원하는 걸해야한다고 생각합니다.

public static class TypeExtensions { 

    public static Type GetTypeDefinition (this Type type) { 
     return type.IsGenericType ? type.GetGenericTypeDefinition() : type; 
    } 

    public static IEnumerable<Type> GetImproperComposingTypes (this Type type) { 
     yield return type.GetTypeDefinition(); 
     if (type.IsGenericType) { 
      foreach (var argumentType in type.GetGenericArguments()) { 
       foreach (var t in argumentType.GetImproperComposingTypes()) yield return t; 
      } 
     } 
    } 

    private static Dictionary<Type , Type> GetInferenceMap (ParameterInfo[] parameters , Type[] types) { 
     var genericArgumentsMap = new Dictionary<Type , Type>(); 
     var match = parameters.All (parameter => parameter.ParameterType.GetImproperComposingTypes().Zip (types[parameter.Position].GetImproperComposingTypes()).All (a => { 
      if (!a.Item1.IsGenericParameter) return a.Item1 == a.Item2; 
      if (genericArgumentsMap.ContainsKey (a.Item1)) return genericArgumentsMap[a.Item1] == a.Item2; 
      genericArgumentsMap[a.Item1] = a.Item2; 
      return true; 
     })); 
     return match ? genericArgumentsMap : null; 
    } 

    public static MethodInfo MakeGenericMethod (this Type type , string name , Type[] types) { 
     var methods = from method in type.GetMethods() 
         where method.Name == name 
         let parameters = method.GetParameters() 
         where parameters.Length == types.Length 
         let genericArgumentsMap = GetInferenceMap (parameters , types) 
         where genericArgumentsMap != null 
         where method.GetGenericArguments().Length == genericArgumentsMap.Keys.Count() 
         select new { 
          method , 
          genericArgumentsMap 
         }; 
     return methods.Select (m => m.method.IsGenericMethodDefinition ? m.method.MakeGenericMethod (m.method.GetGenericArguments().Map (m.genericArgumentsMap).ToArray()) : m.method).SingleOrDefault(); 
    } 

} 

은 그래서

public class Foos { 
    public void Foo<T1 , T2 , T3> (int a , T1 b , IEnumerable<T2> c , Expression<Func<T1 , T3 , string>> d) { 
    } 
    public void Foo<T1 , T2 , T3> (int a , T1 b , IEnumerable<T2> c , Expression<Func<T1 , T3 , int>> d) { 
    } 
    public void Foo() { 
    } 
    public void Foo (string s) { 
    } 
} 

은 내가 원하는 방법을 선택할 수 있습니다 제공 :

var method = typeof (Foos).MakeGenericMethod ("Foo" , new[] { typeof (int) , typeof (DateTime) , typeof (IEnumerable<string>) , typeof (Expression<Func<DateTime , double , int>>) }); 
method.Invoke (new Foos() , new object[] { 1 , DateTime.Now , null , null }); 

var method = typeof (Foos).MakeGenericMethod ("Foo" , Type.EmptyTypes); 
method.Invoke (new Foos() , new object[] { }); 

var method = typeof (Foos).MakeGenericMethod ("Foo" , new[] { typeof (string) }); 
method.Invoke (new Foos() , new object[] { "zozo" }); 

이 아닌 일반적인 방법을 지원하는 것,하지만 분명히 (명시 적으로 일반적인 인수를 지원하지 않습니다), 그리고 아마도 약간의 작업이 필요하지만, 그 핵심입니다.

3

네, 기본적으로 모든 방법을 조사해야합니다. 일반적인 방법으로 바로 가져 오는 방법은

그러나, 한 가지 당신 사용이들이 generic 이외의 동일한 서명으로 과부하 사실 만에 의해 오버로드되어 있습니다 유형 매개 변수 등의 수를 지정하여도 없다 제네릭 형식 매개 변수 당신은이 제약 조건 또는 형식 매개 변수 이름을 사용할 수 없습니다

void Foo<T1>(String x) 
void Foo<T2>(String y) 

예,이 모든 꽤 복잡하다. 내가 너라면 그 일을해야하는 것을 피하려고 꽤 열심히 노력할 것이다.

1

진정한 리플렉션으로 일반적인 방법을 호출하는 것은이 추악한 일일 수 있습니다. 올바른 MethodInfo을 해결하려면 일반적으로 가장 단순한 고유 한 요소를 선택하여 작업하십시오. 이는 일반 매개 변수/메서드 매개 변수 등의 수를 의미 할 수 있습니다. 언 바운드 제네릭 형식 자체를 비교하지 않아도됩니다.

4.0 dynamic으로, 나는 (내가 확인해야 거라고하지만)이이 호출을 많이 만들 수 있다고 생각 간단 (그것은 본질적으로 런타임시 방법/일반적인 해상도를 않기 때문에)하지만, 그렇지 않습니다 확장 메서드 작동 ;-(

또 다른 옵션은 어떤면에서는 조금 더 예뻐 될 수 Expression,하지만 당신은 Compile() 그것 등을해야하고, Expression 복잡 자체입니다는 (사실, 잊지. - 아직 열심히)

0

Type 인스턴스에서 GetMethod 또는 InvokeMember를 호출하면 Binder 클래스의 사용자 지정 하위 클래스를 전달할 수 있습니다. 사용자 지정 바인더는 선택하는 후보 멤버 목록을 수신 할 때 멤버가 선택되는 방식을 변경할 수 있습니다.

관련 문제