使用反射唯一标识方法或构造函数
Uniquely identifying a method or constructor using reflection
我需要为任何给定的 class 唯一标识一个方法或构造函数,以便我可以在稍后阶段调用它。
我曾想过使用 ConstructorInfo.GetHashCode()
和 MethodInfo.GetHashCode()
方法,希望哈希码对于每个继承 MethodBase
的对象都是唯一的。虽然它们是独一无二的,但它们也 change on each run of the program 这意味着这种方法对我来说毫无用处,因为我需要将对象持久保存到数据库中以便以后能够 运行 它(即在重新启动、服务重新启动等之后)。
到目前为止,我真正想出的唯一标识方法和构造函数的唯一方法是
- 首先按名称查找匹配 methods/constructors 的列表
- 迭代匹配methods/constructors看哪个参数列表匹配我想要的
是否有更好的方法可以使用存在于 class 中的反射来唯一标识方法或构造函数,而无需首先迭代匹配的方法名称,然后迭代参数列表以找到第一个匹配项?
methodParams = null;
constructorInfo = null;
var methods = instanceType.GetMethods().Where(m => m.Name == constructorName);//this is required to handle methods that are overloaded
foreach (var method in methods)
{
var internalParams = method.GetParameters();
if (internalParams.Count() == requiredParams.Count())
{
var methodParamDict = internalParams.ToDictionary(x => x.Name, x => String.Empty);
foreach (var requiredParamKey in requiredParams.Keys)
{
if (methodParamDict.ContainsKey(requiredParamKey))
{
methodParamDict[requiredParamKey] = requiredParams[requiredParamKey];
}
}
if (methodParamDict.All(x => x.Value != String.Empty))
{
//set the methodParams to internalParams (i.e. we have found the correct overloaded method)
methodParams = internalParams;
constructorInfo = method as ConstructorInfo;
}
}
}
包括 Stefan 的建议,您可以像这样定义扩展方法 class:
public static class CustomReflectionHelpers
{
public static String CreateUniqueName(this MethodInfo mi)
{
String signatureString = String.Join(",", mi.GetParameters().Select(p => p.ParameterType.Name).ToArray());
String returnTypeName = mi.ReturnType.Name;
if (mi.IsGenericMethod)
{
String typeParamsString = String.Join(",", mi.GetGenericArguments().Select(g => g.AssemblyQualifiedName).ToArray());
// returns a string like this: "Assembly.YourSolution.YourProject.YourClass:YourMethod(Param1TypeName,...,ParamNTypeName):ReturnTypeName
return String.Format("{0}:{1}<{2}>({3}):{4}", mi.DeclaringType.AssemblyQualifiedName, mi.Name, typeParamsString, signatureString, returnTypeName);
}
return String.Format("{0}:{1}({2}):{3}", mi.DeclaringType.AssemblyQualifiedName, mi.Name, signatureString, returnTypeName);
}
}
然后您可以像这样简化比较:
foreach (MethodInfo mi in yourType.GetMethods())
{
if (mi.CreateUniqueName() == stringStoredInDb) { /* do something */ }
}
MethodInfo
是可序列化的。它可能对您有用。
这样做的一个缺点是,当您将二进制文件更新到较新的版本并且仍然想找到该方法时,您会遇到问题。 (对于这种情况,您也应该考虑不使用方法名称。)
我需要为任何给定的 class 唯一标识一个方法或构造函数,以便我可以在稍后阶段调用它。
我曾想过使用 ConstructorInfo.GetHashCode()
和 MethodInfo.GetHashCode()
方法,希望哈希码对于每个继承 MethodBase
的对象都是唯一的。虽然它们是独一无二的,但它们也 change on each run of the program 这意味着这种方法对我来说毫无用处,因为我需要将对象持久保存到数据库中以便以后能够 运行 它(即在重新启动、服务重新启动等之后)。
到目前为止,我真正想出的唯一标识方法和构造函数的唯一方法是
- 首先按名称查找匹配 methods/constructors 的列表
- 迭代匹配methods/constructors看哪个参数列表匹配我想要的
是否有更好的方法可以使用存在于 class 中的反射来唯一标识方法或构造函数,而无需首先迭代匹配的方法名称,然后迭代参数列表以找到第一个匹配项?
methodParams = null;
constructorInfo = null;
var methods = instanceType.GetMethods().Where(m => m.Name == constructorName);//this is required to handle methods that are overloaded
foreach (var method in methods)
{
var internalParams = method.GetParameters();
if (internalParams.Count() == requiredParams.Count())
{
var methodParamDict = internalParams.ToDictionary(x => x.Name, x => String.Empty);
foreach (var requiredParamKey in requiredParams.Keys)
{
if (methodParamDict.ContainsKey(requiredParamKey))
{
methodParamDict[requiredParamKey] = requiredParams[requiredParamKey];
}
}
if (methodParamDict.All(x => x.Value != String.Empty))
{
//set the methodParams to internalParams (i.e. we have found the correct overloaded method)
methodParams = internalParams;
constructorInfo = method as ConstructorInfo;
}
}
}
包括 Stefan 的建议,您可以像这样定义扩展方法 class:
public static class CustomReflectionHelpers
{
public static String CreateUniqueName(this MethodInfo mi)
{
String signatureString = String.Join(",", mi.GetParameters().Select(p => p.ParameterType.Name).ToArray());
String returnTypeName = mi.ReturnType.Name;
if (mi.IsGenericMethod)
{
String typeParamsString = String.Join(",", mi.GetGenericArguments().Select(g => g.AssemblyQualifiedName).ToArray());
// returns a string like this: "Assembly.YourSolution.YourProject.YourClass:YourMethod(Param1TypeName,...,ParamNTypeName):ReturnTypeName
return String.Format("{0}:{1}<{2}>({3}):{4}", mi.DeclaringType.AssemblyQualifiedName, mi.Name, typeParamsString, signatureString, returnTypeName);
}
return String.Format("{0}:{1}({2}):{3}", mi.DeclaringType.AssemblyQualifiedName, mi.Name, signatureString, returnTypeName);
}
}
然后您可以像这样简化比较:
foreach (MethodInfo mi in yourType.GetMethods())
{
if (mi.CreateUniqueName() == stringStoredInDb) { /* do something */ }
}
MethodInfo
是可序列化的。它可能对您有用。
这样做的一个缺点是,当您将二进制文件更新到较新的版本并且仍然想找到该方法时,您会遇到问题。 (对于这种情况,您也应该考虑不使用方法名称。)