C# 多态方法的Type.GetMethod()(泛型和非泛型)
我目前正在创建一种自定义的深度复制对象的方法。我使用一个静态类来实现这个功能C# 多态方法的Type.GetMethod()(泛型和非泛型),c#,reflection,C#,Reflection,我目前正在创建一种自定义的深度复制对象的方法。我使用一个静态类来实现这个功能 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 C
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);
}
}
公共静态类CopyServer
{
公共静态int-copydeph(int-original)
{
归还原件;
}
//未显示:与我使用的所有其他值类型相同(长、浮点等)
公共静态T copydeph(T original),其中T:ICopyAble
{
如果(原始==null)
返回默认值;
如果(原始为ICopyAutofields)
返回CopyAutofields(原始);
返回(T)original.copydeph();
}
私有静态T CopyAutofields(T原始)
{
del代表;
if(!\u copyFunctions.TryGetValue(类型(T),out del))
{
//未显示:参数等的建筑表达式。
foreach(typeof(T).GetFields()中的var fieldInfo)
{
//未显示:检查由自定义属性设置的选项
MethodInfo MethodInfo=typeof(CopyServer).GetMethod(“CopyDeep”,新[]{fieldInfo.FieldType});
//我无法删除第二个参数而不获得含糊不清的MatchException
if(methodInfo==null)
{
抛出新异常($“未为类型{fieldInfo.FieldType}定义CopyDeep”);
}
if(methodInfo.IsGenericMethod)
methodInfo=methodInfo.MakeGenericMethod(fieldInfo.FieldType);
Expression call=Expression.call(methodInfo,readValue);
//未显示:指定表达式
}
//未显示:返回表达式和编译
}
申报表(原件);
}
}
我使用T CopyAutofields
来构建函数(通过构建和编译表达式树),这样我就不必为我想要手动复制的每个类创建复制函数。我用自定义属性控制复制行为(我在上面的代码中留下了这一部分,因为它与我的问题无关)
只要只使用类型为非泛型函数的字段,代码就可以正常工作。但它无法检索我的通用函数T CopyDeep
例如:
//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;
}
}
//这是可行的:
公共类管理器:ICopyAble,ICopyAutofields
{
公共字符串名;
公共字符串LastName;
}
//这并不重要
//含义:typeof(CopyServer).GetMethod(“copyDeep”,new[]{fieldInfo.FieldType});
//在T copyAutofields中,Manager字段返回null,并引发我的异常
公共类雇员:可iCopy,iCopy自动字段
{
公共字符串名;
公共字符串LastName;
公共经理;
}
//这是我在开始使用ICopyAutofields之前使用的。
//这种方法是有效的,但由于我的类通常
//有三个以上的字段,我偶尔会忘记更新
//copyDeep()-如果我添加新的,则返回函数。
公共类雇员:可iCopy,iCopy自动字段
{
公共字符串名;
公共字符串LastName;
公共经理;
公共IModable CopyDeep()
{
var result=新员工();
result.FirstName=CopyServer.copydeph(FirstName);
result.LastName=CopyServer.copydeph(LastName);
result.Manager=CopyServer.copydeph(Manager);
返回结果;
}
}
长话短说:如果具有正确名称的泛型函数和非泛型函数都存在,我需要一种为类型T获取匹配函数的方法。在.NET 4.7.1中,您需要使用方法并过滤结果:
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
深度克隆=序列化+反序列化。@Sinatr谢谢,但我需要更多的控制。这就是我使用属性的目的。例如,一些字段根本不会被复制(主键),而另一些字段有一个字段指示它们被复制的时间。这也需要设置。您也可以使用属性来控制序列化。@Sinatr这是正确的。我在其他地方使用序列化。但它不适合这里。顺便说一句,我强烈建议您遵循.NET命名约定,特别是对于像这样的公共示例代码。这意味着你所有的方法都应该是PascalCase,例如CopyDeep而不是CopyDeep。同样,我建议使用“香草”VisualStudio支撑样式(单独在一行上打开支撑)。这并不是说拥有自己喜欢的支撑风格是错误的,但它可能会让读者分心。非常感谢,这就是我想要的。
public static class CopyAutoFieldServer<T>
{
public static T copyAutofields(T original) { ... }
}