Type.GetMethod() 用于多态方法(泛型和非泛型)



我目前正在创建一种自定义的方式来深度复制我的对象。我为此功能使用静态类。

public static class CopyServer
{
public static int CopyDeep(int original)
{
return original;
}
//not shown: same for all other value types I use (long, float,...)

public static T CopyDeep<T>(T original) where T: ICopyAble
{
if (original == null)
return default;
if (original is ICopyAutofields)
return CopyAutofields(original);
return (T)original.CopyDeep();
}
private static T CopyAutofields<T>(T original)
{
Delegate del;
if (!_copyFunctions.TryGetValue(typeof(T), out del))
{
//not shown: Building expression for parameter etc.
foreach (var fieldInfo in typeof(T).GetFields())
{
//not shown: checking options set by custom attributes
MethodInfo methodInfo = typeof(CopyServer).GetMethod("CopyDeep", new[] { fieldInfo.FieldType });
//I can't remove the second param without getting an AmbiguousMatchException
if (methodInfo == null)
{
throw new Exception($"CopyDeep not defined for type {fieldInfo.FieldType}");
}
if (methodInfo.IsGenericMethod)
methodInfo = methodInfo.MakeGenericMethod(fieldInfo.FieldType);
Expression call = Expression.Call(methodInfo, readValue);
//not shown: Assign Expression
}
//not shown: return Expression and compiling
}
return ((Func<T, T>)del)(original);
}
}

我使用T CopyAutofields<T>来构建函数(通过构建和编译表达式树(,因此我不必为要手动复制的每个类创建复制函数。我使用自定义属性控制复制行为(我将这部分留在上面的代码中,因为它与我的问题无关(。

只要仅使用类型存在非泛型函数的字段,代码就可以正常工作。但是它无法检索我的泛型函数T CopyDeep<T>

例:

//This works:
public class Manager : ICopyAble,ICopyAutofields
{
public string FirstName;
public string LastName;
}
//This doesn't
//Meaning: typeof(CopyServer).GetMethod("copyDeep", new[] { fieldInfo.FieldType }); 
//in T copyAutofields<T> returns null for the Manager-field and my exception gets thrown
public class Employee : ICopyAble,ICopyAutofields
{
public string FirstName;
public string LastName;
public Manager Manager;
}
//This is what I was using before I started using the ICopyAutofields. 
//This approach works, but its' too much too write since my classes usually 
//have way more than three fields and I occasionally forget to update 
//copyDeep()-function if I add new ones.
public class Employee : ICopyAble,ICopyAutofields
{
public string FirstName;
public string LastName;
public Manager Manager;
public IModable CopyDeep()
{
var result = new Employee();
result.FirstName = CopyServer.copyDeep(FirstName);
result.LastName= CopyServer.copyDeep(LastName);
result.Manager= CopyServer.copyDeep(Manager);
return result;
}
}

长话短说:如果同时存在具有正确名称的泛型和非泛型函数,我需要一种方法来获取类型 T 的匹配函数。

在 .NET 4.7.1 中,您需要使用方法GetMethods并筛选结果:

class MyClass
{
public T M<T>(T t) { return default(T); }
public int M(int t) { return 0; }
}
var m = typeof(MyClass).GetMethod("M", new[] { typeof(string) }); // null
var m1 = typeof(MyClass).GetMethods()
.Where(mi => mi.Name == "M" && mi.GetGenericArguments().Any())
.First(); // returns generic method

在.NET Standard 2.1(以及自2.1以来的.NET Core(中,还有另一种方法可以解析泛型类型参数 -Type.MakeGenericMethodParameter,就像你在这个答案中看到的那样。

同样作为解决方法,您可以将copyAutofields<T>方法移动到泛型类,例如CopyAutoFieldServer<T>

public static class CopyAutoFieldServer<T>
{
public static T copyAutofields(T original) { ... }
}

最新更新