2015-04-14 1 views
0

Je suis en train de créer un visualiseur de débogage qui s'applique à divers objets sans que l'ensemble du visualiseur ne devienne une dépendance. Je veux appliquer ce visualiseur à une variété de classes, y compris les imbriqués privés, internes, et avec beaucoup de génériques complexes impliqués (les classes parent et imbriquées). Cela signifie que je crée un objet proxy avec uniquement les données critiques impliquées. Je ne veux pas que mon assemblage principal dépende de l'assemblage du visualiseur, et je ne veux pas que l'assemblage du visualiseur connaisse les intestins de l'assemblage principal.Application d'un visualiseur de débogueur sans dépendances d'assemblage

Dans l'ensemble principal, j'ai quelque chose qui ressemble à ceci:

namespace MainAsm 
{ 
    public interface IVisualizable 
    { 
     DebugProxy DebugVisualizer { get; } 
    } 

    [Serializable] 
    public class DebugProxy 
    { 
     // data required for visualization here 

     public DebugProxy() { } 
     public DebugProxy(IVisualizable source) 
     { 
      var orig = source.DebugVisualizer; 
      // copy properties from orig 
     } 
    } 
} 

Ensuite, pour le Visualiseur, j'ai le code qui ressemble à ceci:

[assembly:System.Diagnostics.DebuggerVisualizer(
    typeof(dbg.Visualizer), 
    typeof(Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource), 
    TargetTypeName="MainAsm.DebugProxy, MainAsm", 
    Description="MainAsm Debug Visualizer")] 

namespace dbg 
{ 
    public class Visualizer : Microsoft.VisualStudio.DebuggerVisualizers.DialogDebuggerVisualizer 
    { 
     protected override void Show(
      Microsoft.VisualStudio.DebuggerVisualizers.IDialogVisualizerService windowService, 
      Microsoft.VisualStudio.DebuggerVisualizers.IVisualizerObjectProvider objectProvider) 
     { 
      object data = objectProvider.GetObject(); 
      if (data == null) 
       return; 
      var t = data.GetType(); 
      var prop = t.GetProperty("DebugVisualizer"); 
      if (prop != null) 
      { 
       data = prop.GetValue(data, null) ?? data; 
      } 

      // use reflection to grab additional properties and open a window 
     } 
    } 
} 

Je veux être en mesure de appliquer un visualiseur à n'importe quelle classe qui sait comment créer un DebugProxy. Je peux évidemment obtenir un visualiseur si je développe un objet et clique sur sa propriété DebugVisualizer, mais je veux que la visualisation soit associée à l'objet de niveau supérieur. Donc, si j'ai quelque chose comme ça:

[System.Diagnostics.DebuggerVisualizer(???)] 
public class MyClass<TThis, T2, T3> : IVisualizable 
    where TThis : MyClass<TThis, T2, T3>, new() 
    where T2 : SomeOtherClass2<T2, T3>, new() 
    where T3 : SomeOtherClass3<T2, T3>, new() 
{ 
    DebugProxy IVisualizable.DebugVisualizer { get { return CreateProxy(); } } 
} 

La question est, qu'est-ce que je dois mettre à la place de ??? pour l'associer à un visualiseur avec MyClass < ,, et ses descendants?

-

  • Si je mets [System.Diagnostics.DebuggerTypeProxy (typeof (DebugProxy))] l'DebugProxy ne se présente pas avec une icône Visualiseur
  • Si je mets [Système .Diagnostics.DebuggerVisualizer ("dbg.Visualizer")], je reçois un NullReferenceException à Microsoft.VisualStudio.DebuggerVisualizers.DebugViewerShim.ManagedShim.DelegateHost.CreateViewer
  • Si je mets [System.Diagnostics.DebuggerVisualizer ("dbg.Visualizer, dbg")], j'obtiens " Impossible de charger le fichier ou l'assembly dbg ou l'une de ses dépendances" même si le journal affiche le chemin correct sous "Initial PrivatePath = "quand il essaie de résoudre l'assemblage.
  • Si je mets [System.Diagnostics.DebuggerVisualizer ("dbg.Visualizer", "Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource")], je reçois " Ne peut pas créer Visualiseur Source Object." La pile d'appel est un série de méthodes dans l'espace de noms DebuggerVisualizeres.DebugViewerShim: "DelegatedHost.CreateViewer" -> "PrivateCallback.MaybeDeserializeAndthrowException" -> "DebugeeHost.CreateSourceInternal" -> "RemoteObjectSourceException"

Répondre

0

Le secret est de créer un VisualizerObjectSource sur mesure et mettre cela dans le GAC:

namespace dbg 
{ 
    public class CustomObjectSource 
     : Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource 
    { 
     private static object ConvertObject(object oldObj) 
     { 
      if (oldObj == null) 
       return null; 
      foreach (var intf in oldObj.GetType().GetInterfaces()) 
      { 
       var prop = intf.GetProperty("DebugVisualizer"); 
       if (prop != null) 
        return prop.GetValue(oldObj, null); 
      } 
      return oldObj; 
     } 

     public override void TransferData(object target, Stream incomingData, Stream outgoingData) 
     { 
      base.TransferData(ConvertObject(target), incomingData, outgoingData); 
     } 

     public override object CreateReplacementObject(object target, Stream incomingData) 
     { 
      return ConvertObject(base.CreateReplacementObject(ConvertObject(target), incomingData)); 
     } 

     public override void GetData(object target, Stream outgoingData) 
     { 
      base.GetData(ConvertObject(target), outgoingData); 
     } 
    } 
} 

Ensuite, mettre l'attribut suivant sur les classes qui mettent en œuvre IVisualizable:

[System.Diagnostics.DebuggerVisualizer(
    "dbg.Visualizer, dbg, Version=1.0.0.0, Culture=neutral, PublicKeyToken=???", 
    "dbg.CustomObjectSource, dbg, Version=1.0.0.0, Culture=neutral, PublicKeyToken=???"] 

Où ???est la clé publique de l'assemblée.

Il est très important que l'assembly avec CustomObjectSource entre dans le GAC, car cela garantit qu'il peut être chargé dans le domaine de l'application debugee quel que soit le chemin de base défini. Assurez-vous qu'il a un nom fort et utilisez "gacutil/f/i dbg.dll" à partir d'une invite de commande Visual Studio pour l'installer.

Ensuite, lorsque vous essayez de visualiser votre classe, il charge CustomObjectSource dans votre domaine d'application, utilise la méthode CreateReplacementObject pour le convertir en type sérialisable et effectue la sérialisation sur l'objet DebugProxy au lieu du type d'origine.