观察ReSharper灯泡操作的用法

时间:2013-09-23 12:47:22

标签: c# visual-studio-2010 resharper

我可以通过在IActionManager [1]已知的每个UpdatableAction上安装IActionHandler来观察ReSharper Actions的执行。不幸的是,Bulb Actions(Context Actions和Quickfixes [2])不是ReSharper中的Actions,因此Action Manager不知道。此外,似乎没有类似于ActionManger for Bulb Actions的东西。

  • 是否有一些(可能是通用的)方法来处理所有Bulb操作?
  • 可以在这里使用像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

1 个答案:

答案 0 :(得分:0)

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

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

[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);
    }
  }
}

优先级的返回值确保我的提供程序被称为所有现有提供程序的最后一个。这导致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的所有用法。我很难找到自己的方式,但终于击败了挑战。希望这可以帮助别人,某个地方,某些人!