2016-08-02 27 views
4

Ich mache einen verwalteten .NET-Debugger mit MDBG-Beispiel.Generischer Typ func-eval mit ICorDebugEval

MDBG hat keine Unterstützung für Property Getter Bewertung, die ich hinzufügen möchte. Bitte beachten Sie, Struktur folgende Klasse:

public abstract class Base<T>{ 
     public string SomeProp {get;set;} 
    } 

    public class A : Base<int>{ 

    } 

An einem gewissen Punkt der Zeit eine Instanz von A Ich erstelle und an einem Haltepunkt zu stoppen ist es Zustand zu bewerten.

Im Watchword-Fenster des Debuggers stelle ich "this.SomeProp" vor, das eine func-eval der get_SomeProp-Methode für dieses Objekt ausführen und einen Nullwert für den gegebenen Fall zurückgeben soll.

Das erste Problem, das ich festgestellt habe, war die Tatsache, dass get_SomeProp für die Basisklasse definiert wurde, also musste ich alle TypeDefs/TypeRefs/TypeSpecs in der Klassenhierarchie durchlaufen, um die Funktion zu finden.

Aber nachdem es gefunden wurde,

Aufruf in
ICorDebugEval.CallFunction(function.CorFunction, new[] {@object.CorValue}); 

Folge: Type: Der generische Typ mit der falschen Anzahl von generischen Argumenten in der Montage verwendet wurde.

Wie ich festgestellt habe passiert, weil nicht-generische Funktion in einer generischen Klasse (Base) definiert ist, also wenn ich es auswerte, sollte ich auch generische Parameter der Klasse angeben.

dies geschehen könnte

ICorDebugEval2.CallParameterizedFunction(function.CorFunction, 
    genericArguments, 
    functionArguments); 

Das Problem ist, dass ich keine Ahnung, wie Arten von Klasse generischen Parameter zu extrahieren, nur Funktion, die ich auf dem ich bewerten wollen bewerten und Instanz wollen es.

Hier einige Code, den ich zur Zeit bin mit: Jeder Vorschlag/Beratung wird sehr geschätzt

private MDbgValue EvaluatePropertyGetter(MDbgFrame scope, MDbgValue @object, string propertyName) { 
     var propertyGetter = $"get_{propertyName}"; 
     var function = ResolveFunctionName(
      scope.Function.Module.CorModule.Name, 
      @object.TypeName, 
      propertyGetter, 
      scope.Thread.CorThread.AppDomain); 

     if (function == null) { 
      throw new MDbgValueException("Function '" + propertyGetter + "' not found."); 
     } 

     var eval = Threads.Active.CorThread.CreateEval(); 
     var typeToken = function.CorFunction.Class.Token; 
     var type = function.Module.Importer.GetType(typeToken); //checked that type containing function is generic 
     if (type.IsGenericType) { 
      //------------->need to get class'es generic param types<------------ 
      var genericType1 = this.ResolveType("System.Object"); // just a stub 
      eval.CallParameterizedFunction(function.CorFunction, new CorType[] {genericType1}, new[] {@object.CorValue}); 
     } 
     else { 
      eval.CallFunction(function.CorFunction, new[] {@object.CorValue}); 
     } 

     Go().WaitOne(); 
     if (!(StopReason is EvalCompleteStopReason)) { 
      // we could have received also EvalExceptionStopReason but it's derived from EvalCompleteStopReason 
      Console.WriteLine("Func-eval not fully completed and debuggee has stopped"); 
      Console.WriteLine("Result of funceval won't be printed when finished."); 
     } 
     else { 
      eval = (StopReason as EvalCompleteStopReason).Eval; 
      Debug.Assert(eval != null); 

      var cv = eval.Result; 
      if (cv != null) { 
       var mv = new MDbgValue(this, cv); 
       return mv; 
      } 
     } 
     return null; 
    } 

!

Grüße,


Lösung

Dank @ Brian Reichle herausragende Antwort kam ich mit dieser Lösung:

if (type.IsGenericType) { 
      //getting Type's Generic parameters 
      var typeParams = GetGenericArgs(@object.CorValue.ExactType, function.CorFunction.Class.Token); 
      eval.CallParameterizedFunction(function.CorFunction, typeParams.ToArray(), new[] {@object.CorValue}); 
     } 

Und die Funktion selbst:

private List<CorType> GetGenericArgs(CorType corType, int classTk) { 
     if (corType == null) 
      return null; 
     List<CorType> list = new List<CorType>(); 

     var param =corType.TypeParameters; 
     var args = GetGenericArgs(corType.Base, classTk); 

     if (classTk == corType.Class.Token) { 
      list.AddRange(param.Cast<CorType>()); 
     } 

     if (args != null) { 
      list.AddRange(args);} 

     return list; 
    } 

Antwort

2

Sie können ICorDebugValue2::GetExactType auf dem Wertobjekt verwenden, um eine Instanz von A, die die ICorDebugType für Typen A, ICorDebugType::GetBase() zu bekommen seine Basisklasse zu erhalten (Base<int>) und ICorDebugType::EnumerateTypeParameters auf dem Basistyp gibt es Argumente zu bekommen.

+0

Danke nochmals, Brian, dass du mir geholfen hast! Unglücklicherweise gibt die Verwendung von GetExactType den geschlossenen Typ A zurück und EnumerateTypeParameters gibt 0 params zurück, da dieser Typ keine generischen Parameter hat. Ich denke, ich muss Base irgendwie EnumerateTypeParams verwenden.Sollte ich in die Vererbungshierarchie gehen, um diesen Typ zu bekommen, oder fehlt mir etwas? – 3615

+0

Entschuldigung, ich habe den Anruf zu GetBase() vergessen :) –

+0

Danke! Ich habe es bereits mit GetBase versucht und es funktioniert für ein einfaches Szenario, das ich in der Frage habe. Derzeit probiere ich ein komplizierteres Szenario mit A: B aus, während B : C . In diesem Fall navigiere ich zu B und bekomme seine generischen Parameter. Aber das Ergebnis der Auswertung ist in diesem Fall ** TargetParameterCountException **: Anzahl der angegebenen Parameter stimmt nicht mit der erwarteten Anzahl überein. – 3615