gpt4 book ai didi

c# - 如何对运行时已知的类型执行方法重载解析?

转载 作者:太空宇宙 更新时间:2023-11-03 15:45:13 24 4
gpt4 key购买 nike

我有一个包含方法重载的类:

public static void Foo(string a, string b)
public static void Foo(DateTime a, DateTime b)
public static void Foo<T>(ICollection<T> a, T b)
public static void Foo<T>(T a, ICollection<T> b)
public static void Foo<T>(ICollection<T> a, ICollection<T> b)
public static void Foo<T, U>(T a, U b) where T : IComparable
public static void Foo<T, U>(T a, U b)

我以这种方式在运行时检索所有方法:

var methods = typeof(MyClass).GetMethods(BindingFlags.Public | BindingFlags.Static);

对于两个给定的参数类型(例如:typeof(int)typeof(List<int>)),我想动态选择最合适的方法。

到目前为止我尝试/检查的内容:

  • Binder.SelectMethod() : 该方法不支持泛型。
  • typeof().IsAssignableFrom() :同上。对泛型参数有一些支持(例如:提供泛型参数 T 及其对类型 int 的约束将被正确评估)但不支持带参数的泛型类型(例如:List<int> vs List<> 或 vs List<T>(此类型将来自泛型方法和可能 T 包括一些约束))

  • 使用所有泛型方法的输入参数调用 MakeGenericMethod(),并捕获参数异常直到没有异常:丑陋。它可能需要完成一些额外的工作,因为我提供给 MakeGenericMethod() 的类型可能与我收到的初始类型不完全相同(例如:我有 typeof(List<int>), typeof(int) 而我应该提供 typeof(int)MakeGenericMethod()

我知道这是一个复杂的话题,而且不是小问题,但有一些问题已经解决,应该会让事情变得更容易:

  • 所有方法都有两个参数和相同的返回类型
  • 没有可选类型,没有数组。
  • 泛型方法不再有一个或两个泛型参数,参数总是以相同的顺序排列。
  • 不需要支持协变/逆变
  • 方法已经按“优先级”排序。这就是为什么没有约束的通用类位于此列表的末尾。一旦一种方法匹配,我们就可以采用它并忽略其他方法

我想知道是否有办法使用 C# Framework 中的现有类/方法解决这些重载(无需重新发明轮子),如果不可能,可能的解决方案是什么(自定义代码)

最佳答案

考虑到您描述的先决条件,您可以这样做:

static void ExecuteCase(object a, object b)
{
var method = GetMethod(typeof(Bar).GetMethods(BindingFlags.Public | BindingFlags.Static), a.GetType(), b.GetType());
if (method != null) { method.Invoke(null, new object[] {a, b}); }
else { /* Handle method not found */ }
}

GetMethod 是:

private static MethodInfo GetMethod(IEnumerable<MethodInfo> methods, Type typeA, Type typeB)
{
foreach (var method in methods)
{
List<MethodInfo> candidates = new List<MethodInfo>();
if (!method.IsGenericMethod) { candidates.Add(method); }
else
{
MethodInfo genericMethod;
if (IsParameterOfGeneric(typeA, typeB) && TryMakeGenericMethod(method, typeB, typeB, out genericMethod)) candidates.Add(genericMethod);
if (IsParameterOfGeneric(typeB, typeA) && TryMakeGenericMethod(method, typeA, typeA, out genericMethod)) candidates.Add(genericMethod);
if (typeA.IsGenericType && typeB.IsGenericType && TryMakeGenericMethod(method, typeA.GetGenericArguments()[0], typeB.GetGenericArguments()[0], out genericMethod)) candidates.Add(genericMethod);
if (TryMakeGenericMethod(method, typeA, typeB, out genericMethod)) candidates.Add(genericMethod);
}

foreach (var candidate in candidates)
{
var args = candidate.GetParameters();
if (args[0].ParameterType.IsAssignableFrom(typeA) && args[1].ParameterType.IsAssignableFrom(typeB)) return candidate;
}
}

return null;
}

private static bool IsParameterOfGeneric(Type generic, Type parameter)
{
if (!generic.IsGenericType) return false;
return generic.GetGenericArguments()[0] == parameter;
}

private static bool TryMakeGenericMethod(MethodInfo method, Type typeA, Type typeB, out MethodInfo genericMethod)
{
genericMethod = null;
try
{
genericMethod = method.GetGenericArguments().Length == 1
? method.MakeGenericMethod(typeA)
: method.MakeGenericMethod(typeA, typeB);

return true;
}
catch (ArgumentException ex)
{
if (ex.Message.Contains("violates the constraint of type")) return false;
throw;
}
}

仅供引用,why use try-catch on TryMakeGenericMethod

关于c# - 如何对运行时已知的类型执行方法重载解析?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28384444/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com