Универсальный тип func-eval с использованием ICorDebugEval

Я делаю управляемый.NET отладчик, используя пример MDBG.

MDBG не поддерживает оценку получателей свойств, которую я пытаюсь добавить. Пожалуйста, рассмотрите следующую структуру класса:

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

    public class A : Base<int>{

    }

В какой-то момент я создаю экземпляр A и останавливаюсь на точке останова, чтобы оценить его состояние.

В окне наблюдения моего отладчика я ввожу this.SomeProp, который должен выполнить функцию get_SomeProp для этого объекта и вернуть нулевое значение для данного случая.

Первой проблемой, с которой я столкнулся, был тот факт, что get_SomeProp был определен для базового класса, поэтому мне пришлось пройти через все TypeDefs/TypeRefs/TypeSpecs в иерархии классов, чтобы найти функцию.

Но после того, как это было найдено, звоню

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

привело к: TypeLoadException: универсальный тип использовался с неправильным числом универсальных аргументов в сборке.

Как я понял, это происходит потому, что неуниверсальная функция определена в универсальном классе (Base), поэтому, когда я ее оцениваю, я также должен указать общие параметры класса.

Это можно сделать с помощью

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

Проблема в том, что я понятия не имею, как извлечь типы общих параметров класса, имея только функцию, которую я хочу оценить, и экземпляр, по которому я хочу это оценить.

Вот код, который я сейчас использую:

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

Любое предложение / совет с благодарностью!

С Уважением,


Решение

Благодаря выдающемуся ответу @Brian Reichle я придумал это решение:

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

И сама функция:

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

1 ответ

Решение

Вы можете использовать ICorDebugValue2::GetExactType для объекта значения, представляющего экземпляр A получить ICorDebugType для типа A, ICorDebugType:: GetBase (), чтобы получить его базовый класс (Base<int>) и ICorDebugType::EnumerateTypeParameters для базового типа, чтобы получить аргументы его типа.

Другие вопросы по тегам