【问题标题】:How to refactor when reflection is used to get methods by name?使用反射按名称获取方法时如何重构?
【发布时间】:2014-03-24 11:15:19
【问题描述】:

假设我通过以下方式获得 MethodInfo:

Assembly assembly = Assembly.Load(assemblyName);
Type type = assembly.GetType(nameSpaceName+"."+className);
MethodInfo mi = type.GetMethod("myMethod", bf); // bf are the binding flags.

但后来我决定更改myMethod 的大小写/名称。

有没有办法:

  1. 重构以更改字符串中的名称。
  2. 更改反射调用,使其在不使用方法名称作为字符串的情况下获取方法?

这样做的原因是我可以测试需要使用反射的代码,但我宁愿不要求没有人更改代码中方法的名称。

【问题讨论】:

  • 一句话:小心!这实际上完全取决于您使用反射的方式和原因。 myMethod这个名字有什么特别之处?该类是否没有实现接口或类似的东西?
  • 嗯...我猜 myMethod 的特殊之处在于我知道另一个方法调用它,myMethodCaller。因此,当我测试时,我希望将 myMethod 的调用者视为 myMethodCaller。我想我可以期望不要改变这两种方法......但我不喜欢那样。
  • 在您的场景中是否可以让动态加载的程序集中的类型实现接口?这样你就不必通过反射调用方法(但仍然可以有一个插件架构)。
  • @user420667:那么你的调用者是如何调用代码的呢?直接地?如果是这样,你为什么不能这样做?
  • @JS: B/c 测试的重点是显示其他方法,比如 MethodInfo getCaller(MethodInfo mi),有效。

标签: c# reflection refactoring


【解决方案1】:

如果您使用 Visual Studio 进行重构,则可以选择在文字字符串和 cmets 中搜索名称并进行更改。不过,我强烈建议在使用该选项时使用预览,以验证您是否只更改了预期的部分。

当然,您可以使用像internal const string methodName = "methodName"; 这样的常量,这样您就只有一次文字字符串。当您重构方法名称时,您可以手动更改一个字符串文字。您还可以更轻松地重命名 methodName

【讨论】:

  • 感谢您提请我注意。从来没有仔细看过重构对话框。
  • 如果方法名称与 cmets 中常用的字符串匹配,这种方法会变得非常难看。一定有更好的方法。
  • @GregC:这正是我告诉他使用预览版的原因。否则它会变得非常混乱。
【解决方案2】:

您可以使用自定义属性,并使用此属性装饰您的方法。然后,您可以通过属性中定义的 ID 来获取方法,而不是通过名称获取方法。这样,方法名称可以根据需要随时更改……只是一个想法。

[AttributeUsage(AttributeTargets.Method)]
public class CustomMethodAttribute : Attribute
{
    public string ID { get; set; }
}

用法:

[CustomMethodAttribute(ID = "UniqueIDHere")]
public void Test()
{

}

【讨论】:

  • 嗯...有趣的解决方案。我猜你必须将它与 MethodInfo.GetCustomAttributes(CustomMethodAttribute, false/true) 结合使用。还是有别的办法?
  • 是的 - 只是您的另一种选择。让您可以更好地控制命名约定,并且您可以自定义 GhostDoc 以在添加 XML 注释时添加属性。
【解决方案3】:

您对所讨论的类型有具体的参考吗?

即使你没有明确地拥有它,你也可以将方法设为通用。

public void TestMethod<TargetType>(object o)
{
    if (typeof(TargetType).IsAssignableFrom(o.GetType())) {
        TargetType strongType = o as TargetType;
        strongType.myMethod();
    }
}

事实上,你完全可以不用反思来做到这一点:

public void TestMethod<TargetType>(object o)
{
    if (o is TargetType) {
        TargetType strongType = o as TargetType;
        strongType.myMethod();
    }
}

【讨论】:

  • 好的,谢谢。我知道我可以直接调用它,但这不是我想要做的事情。
  • @user420667,如果您必须使用动态调用,那么显然您不能在编译时按名称绑定到方法。在这种情况下,我将只使用 const string 作为方法名称,并在您动态调用的任何位置引用此 const。
【解决方案4】:

对于方法和属性,请尝试使用表达式树。 您可以从中获取与反射相关的信息,从而节省编译时检查并启用自动重构。 我相信您也可以获得与程序集相关的信息和命名空间名称。 只需编写几个可以从表达式树中检索此类信息的辅助函数。

你可以找到几个辅助函数here 他们允许编写这样的代码:

FirePropertyChanged(() => PropertyName);

相同
FirePropertyChanged("PropertyName");

【讨论】:

    猜你喜欢
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 2014-08-11
    • 2013-09-18
    相关资源
    最近更新 更多