Dadurch wird eine Liste aller in einem bestimmten Typ definierten Erweiterungsmethoden zurückgegeben, einschließlich der generischen:
public static IEnumerable<KeyValuePair<Type, MethodInfo>> GetExtensionMethodsDefinedInType(this Type t)
{
if (!t.IsSealed || t.IsGenericType || t.IsNested)
return Enumerable.Empty<KeyValuePair<Type, MethodInfo>>();
var methods = t.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(m => m.IsDefined(typeof(ExtensionAttribute), false));
List<KeyValuePair<Type, MethodInfo>> pairs = new List<KeyValuePair<Type, MethodInfo>>();
foreach (var m in methods)
{
var parameters = m.GetParameters();
if (parameters.Length > 0)
{
if (parameters[0].ParameterType.IsGenericParameter)
{
if (m.ContainsGenericParameters)
{
var genericParameters = m.GetGenericArguments();
Type genericParam = genericParameters[parameters[0].ParameterType.GenericParameterPosition];
foreach (var constraint in genericParam.GetGenericParameterConstraints())
pairs.Add(new KeyValuePair<Type, MethodInfo>(parameters[0].ParameterType, m));
}
}
else
pairs.Add(new KeyValuePair<Type, MethodInfo>(parameters[0].ParameterType, m));
}
}
return pairs;
}
Hier gibt es nur ein Problem: Der zurückgegebene Typ ist nicht derselbe, den Sie mit typeof (..) erwarten würden, da es sich um einen generischen Parametertyp handelt. Um alle Erweiterungsmethoden für einen bestimmten Typ zu finden, müssen Sie die GUID aller Basistypen und Schnittstellen des Typs wie folgt vergleichen:
public List<MethodInfo> GetExtensionMethodsOf(Type t)
{
List<MethodInfo> methods = new List<MethodInfo>();
Type cur = t;
while (cur != null)
{
TypeInfo tInfo;
if (typeInfo.TryGetValue(cur.GUID, out tInfo))
methods.AddRange(tInfo.ExtensionMethods);
foreach (var iface in cur.GetInterfaces())
{
if (typeInfo.TryGetValue(iface.GUID, out tInfo))
methods.AddRange(tInfo.ExtensionMethods);
}
cur = cur.BaseType;
}
return methods;
}
Vollständig sein:
Ich behalte ein Wörterbuch mit Typinfoobjekten, das ich beim Iterieren aller Typen aller Assemblys erstelle:
private Dictionary<Guid, TypeInfo> typeInfo = new Dictionary<Guid, TypeInfo>();
wo das TypeInfo
definiert ist als:
public class TypeInfo
{
public TypeInfo()
{
ExtensionMethods = new List<MethodInfo>();
}
public List<ConstructorInfo> Constructors { get; set; }
public List<FieldInfo> Fields { get; set; }
public List<PropertyInfo> Properties { get; set; }
public List<MethodInfo> Methods { get; set; }
public List<MethodInfo> ExtensionMethods { get; set; }
}