-1

我可以通过在 IActionManager [1] 已知的每个 UpdatableAction 上安装 IActionHandler 来观察 ReSharper Actions 的执行情况。不幸的是,灯泡动作(上下文动作和快速修复 [2])不是 ReSharper 中的动作,因此动作管理器不知道。此外,似乎没有类似于灯泡动作的 ActionManger 的东西。

  • 是否有一些(可能是通用的)方法来处理所有灯泡操作?
  • 可以在这里使用 ActionHandler 之类的东西来了解 Bulb-Action 的执行情况吗?

以防万一:我在 Visual Studio 2010 中使用 ReSharper 8

提前致谢!

[1] http://confluence.jetbrains.com/display/NETCOM/2.03+Actions+and+Menu+Items+%28R8%29

[2] http://confluence.jetbrains.com/display/NETCOM/2.06+Quick-Fixes+and+Context+Actions+%28R8%29

4

1 回答 1

0

我终于找到了解决我的问题的方法!它涉及一点投射和反射,但实际上在我迄今为止所做的所有测试中都可以稳定运行。我进行如下操作:

R# 具有 IBulbItemsProvider 接口,其实现被动态加载并查询灯泡项,即,每当 R# 菜单之一打开时,菜单项包装灯泡动作。我现在实现了以下提供程序:

[SolutionComponent]
public class BulbItemInstrumentationComponent : IBulbActionprovider
{
  public int Priority { get{ return int.MaxValue; } }

  public object PreExecute(ITextControl tc) { return null; }

  public void CollectActions(IntentionsBulbItems ibis, ...)
  {
    var bulbItems = ibis.AllBulbMenuItems;
    foreach (var execItem in bulbItems.Select(item => item.ExecutableItem))
    {
      var proxy = execItem as IntentionAction.MyExecutableProxi;
      if (proxy != null)
      {
        proxy.WrapBulbAction();
        continue;
      }

      var exec = execItem as ExecutableItem;
      if (exec != null)
      {
        exec.WrapBulbAction();
        continue;
      }

      throw new Exception("unexpected item type: " + execItem.GetType().FullName);
    }
  }
}

Priority 的返回值确保我的提供程序在所有现有提供程序中被调用。这导致 CollectAction() 的参数 IntensionsBulbItems 已经包含从其他提供程序收集的 BulbMenuItems。

然后我遍历所有这些项目并安装我的观察包装器。因此,我需要将项目可执行文件向下转换为它们的实际类型。对于来自 R#Core 的灯泡项目,上述两种类型似乎是唯一使用的类型。来自 R#Extensions 的提供程序实际上可能使用其他类型,在这种情况下,循环结束时的异常将在未来被更慷慨的处理所取代;)

包装本身在 WrapBulbAction() 扩展方法中实现。这些看起来如下:

static class BulbItemInstrumentationExtensions
{
  private static readonly MethodInfo MyExecutableProxiBulbActionSetter =
    typeof (IntentionAction.MyExecutableProxi).GetProperty("BulbAction").GetSetMethod(true);
  private static readonly FieldInfo ExecutableItemActionField =
    typeof (ExecutableItem).GetField("myAction", BindingFlags.NonPublic | BindingFlags.Instance);

  public static void WrapBulbAction(this IntentionAction.MyExecutableProxi proxi)
  {
    var originalBulbAction = proxy.BulbAction;
    var bulbActionProxy = new LoggingBulbActionProxy(originalBulbAction);
    MyExecutableProxiBulbActionSetter.Invoke(proxy, new object[] {bulbActionProxy});
  }

  public static void WrapBulbAction(this ExecutableItem exec)
  {
    var originalAction = (Action) ExecutableItemActionField.GetValue(exec);
    var actionProxy = new LoggingActionProxy(originalAction);
    var newAction = (Action) (wrapper.Execute);
    ExecutableItemActionField.SetValue(exec, newAction);
  }
}

LoggingBulbActionProxy 实现 IBulbAction 本身并将所有调用委托给传递给其构造函数的 IBulbAction,从而记录对 Execute() 的所有调用。LoggingActionProxy 是一个声明 Execute() 方法的类,它处理日志记录,然后委托给传递给构造函数的 Action。

现在我终于可以记录 R#BulbActions 的所有用法了。很难找到自己的方式,但最终战胜了挑战。希望这可以帮助某人,某处,某时!

于 2013-10-04T14:57:01.170 回答