2016-11-12 57 views
-2

如何获取“字符串”类型的所有方法,并使用所有扩展方法(如“Aggregate”,“Select”和其他通过c#反射?我知道,大多数类型实现IEnumerable接口<>,而这一切的扩展方法枚举类与第一个通用parametr TSource.Ok ...代码:字符串类型的所有扩展方法

var type = typeof(string).GetMethods(); //i get all methods string type 
//I want get for this type all extensions methods like "Select" "Where" 
//so i get all interfaces 
type.GetInterfaces(); 
//ICompareble 
//ICloneable 
//... 
//IEnumearable, but all this interfaces don't have extensions methods 
//They locate in Enumerable class 
//how i can use string type go to Enumerable class and get all this methods 
//Somthigs like this 
typeof(Enumerable).GetMethods(); //i want get all this methods but using type "string" 
//Aggregate 
//Select 
//where 
+1

我认为你很容易发布一个可重现的代码,以便我们的机器可以在我们的机器上进行测试.. –

+0

This link [link] http://stackoverflow.com/questions/299515/reflection- to-identify-extension-methods方法不起作用,因为他使用了第一个参数typeof(string),在我的版本中,这个方法具有第一个参数通用TSource。 – itihonov

回答

1

扩展方法当然可以在不同的组件来定义,所以第一个问题是我们关心哪些程序集。我们将与

var assemblies = GetType().Assembly 
    .GetReferencedAssemblies() 
    .Select(an => Assembly.Load(an)) 
    .Concat(Enumerable.Repeat(GetType().Assembly, 1)); 

到(在实例方法或属性的上下文中)获得当前的装配和所有它引用开始,因为这是对扩展方法可用那里,然后可行的来源。其他用途将有其他出发点。

现在我们需要把所有的扩展方法:

var availableExtensionMethods = assemblies 
    // First get all the types 
    .SelectMany(asse => asse.GetExportedTypes()) 
    // Cut out some which cannot be static classes first 
    .Where(t => t.IsAbstract && t.IsSealed && t.GetConstructors().Length == 0) 
    // Get all their methods. 
    .SelectMany(t => t.GetMethods()) 
    // Restrict to just the extension methods 
    .Where(m => m.GetCustomAttributes().Any(ca => ca is System.Runtime.CompilerServices.ExtensionAttribute) 
    // An extension method must have at least one parameter, but we'll rule out being 
    // messed up by some strangely defined method through weird direct use of 
    // the ExtensionAttribute attribute 
    && m.GetParameters().Length != 0) 
    // Get an object with the method and the first parameter we'll use below. 
    .Select(m => new {Method = m, FirstParam = m.GetParameters()[0]}); 

现在,那些直接在基类(SomeMethod(this object arg))的stringSomeMethod(this string arg))来定义将是:

var stringExtensions = availableExtensionMethods 
    .Where(info => info.FirstParam.ParameterType.IsAssignableFrom(typeof(string))) 
    .Select(info => info.Method); 

以上内容将包括(this IEnumerable<char> arg)。要获得一个泛型类型的字符串器具总体定义(如(this IEnumerable<T> arg)我们将使用:

var stringGenericInterfaces = typeof(string).GetInterfaces() 
    .Where(i => i.IsGenericType) 
    .Select(i => i.GetGenericTypeDefinition()); 
    var extensionsOnGenericInterfaces = from info in 
     availableExtensionMethods.Where(aem => aem.FirstParam.ParameterType.ContainsGenericParameters) 
     from inter in stringGenericInterfaces 
     where info.FirstParam.ParameterType.GetGenericTypeDefinition().IsAssignableFrom(inter) 
     select info.Method; 

然后,您可以Union这些结合在一起,以获得大量的

我没有列入约束检查这里虽然。

+0

非常感谢你的配合,这是工作。我无法评估你的答案,因为我的声誉很差。这是我的第一个问题,我有“-2”,不知道为什么,可能是因为我英文不好:)) – itihonov

0

字符串的扩展方法都位于枚举类和IEnumerable接口这是在System.Linq的命名空间的mscorlib装配 你可以在System.Linq的扩展方法的名称在这样的方式:

//The actual method to find all extension methods in the assembly 
    //that take IEnumerable<TSource> or TSource as parameters. 
    public static IEnumerable<MethodInfo> GetExtensionMethods(Assembly assembly,Type extendedType) 
    { 
     var query = from type in assembly.GetTypes() 
     where type == typeof(Enumerable) 
     from method in type.GetMethods(BindingFlags.Static 
     | BindingFlags.Public | BindingFlags.NonPublic) 
     where method.IsDefined(typeof(ExtensionAttribute), false) 
     where (method.GetParameters()[0].ParameterType.IsGenericType 
     | (method.GetParameters()[0].ParameterType.ContainsGenericParameters) 
     select method; 

     return query; 
    } 

    //Get the assembly System.Linq 
    Assembly thisAssembly = Assembly.GetAssembly(typeof(Enumerable)); 
    foreach (MethodInfo method in GetExtensionMethods(thisAssembly, 
     typeof(string))) 
    { 
     Console.WriteLine(method); 
    }