C # Reflection - Могу ли я проверить, если один метод вызывает другой - PullRequest
3 голосов
/ 25 января 2010

Я ищу способ, чтобы метод «A» вызывал метод «B». Таким образом, сделка примерно ..

class one
{
    internal static void MethodA()
    {
        //Do Something here.  SHOULD be calling B.
    }

    void MethodB()
    {
         //MUST be called by MethodA.
    }
}

class two
{
    internal void MethodA()
    {
        //Test that MethodA calls MethodB
    }
}

Я должен отметить, что я застрял на .Net 2.0 для этого, так что ExpressionTrees бесполезны. Я даже не уверен, что они помогут, но это была моя первоначальная мысль.

РЕДАКТИРОВАТЬ: Это для внутреннего инструмента для визуализации цикломатической сложности источника, поэтому я не беспокоюсь о нарушении инкапсуляции здесь. Кроме того, вероятно, это нужно будет сделать, просто используя System.Reflection.

Ответы [ 6 ]

4 голосов
/ 25 января 2010

Во многих случаях это выполнимо, но с вашей стороны придется набирать текст. Первое, что вы хотите сделать, это использовать класс ILReader - здесь есть набросок один тот, который Флориан Дойон опубликовал ). Затем вы хотите обернуть это в класс, как это:

public class MethodCalls : IEnumerable<MethodInfo>
{
    MethodBase _method;

    public MethodCalls(MethodBase method)
    {
        _method = method;
    }

    public IEnumerator<MethodInfo> GetEnumerator()
    {
        // see here: http://blogs.msdn.com/haibo_luo/archive/2005/10/04/476242.aspx
        ILReader reader = new ILReader(_method);

        foreach (ILInstruction instruction in reader) {
            CallInstruction call = instruction as CallInstruction;
            CallVirtInstruction callvirt = instruction as CallVirstInstruction;
            if (call != null)
            {
                yield return ToMethodInfo(call);
            }
            else if (callvirt != null)
            {
                yield return ToMethodInfo(callvirt);
            }
        }
    }
}

MethodInfo ToMethodInfo(CallInstruction instr) { /* ... */ }

MethodInfo ToMethodInfo(CallVirtInstruction instr) { /* ... */ }

Ни один из двух вариантов ToMethodInfo не определен, потому что CallInstruction также не определена. Тем не менее, этот план, надеюсь, превратит вашу проблему в:

public static bool Calls(MethodBase caller, MethodInfo callee)
{
    return new MethodCalls(caller).Contains(callee);
}
2 голосов
/ 25 января 2010

Существует фрагмент кода проекта для считывателя IL, хотя вам может потребоваться его исправление для поддержки обобщений.

http://www.codeproject.com/KB/cs/sdilreader.aspx

Веселись!

2 голосов
/ 25 января 2010

Вы можете использовать Mono Cecil , чтобы отразить на теле метода MethodA и искать call/callvirt инструкции, которые вызывают MethodB.

1 голос
/ 25 января 2010

вы не можете вручную катить макет объекта? Это зависит от того, можете ли вы сделать MethodB видимым и виртуальным.

class one
{
    internal static void MethodA()
    {
        //Do Something here.  SHOULD be calling B.
    }

    internal virtual void MethodB()
    {
         //MUST be called by MethodA.
    }
}

class three : one
{
    public bool wasCalled;
    override void MethodB()
    {
         wasCalled=true;
    }
}


class two
{
    internal void MethodA()
    {
        three.ClassA();
        if (three.wasCalled)
        {
        }
    }
} 
1 голос
/ 25 января 2010

Если честно, я думаю, вы слишком любопытны на предмет реализации внутренних деталей класса.

Что касается ответа, я приведу контрапункт, рассмотрим:

void MethodB() {
    var methodA = BuildDelegate("Method" + "A");
    methodA();
}
1 голос
/ 25 января 2010

Может быть, не совсем то, что вы ищете, но вы можете написать модульные тесты, используя фальшивый фреймворк. Эта фиктивная среда (например, Moq) может проверять, что метод вызывался в макете при выполнении некоторого кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...