c# – NDepend和Dependency Injection – 如何连接点?

请使用MEF作为依赖注入框架观察以下简单程序:

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

namespace ConsoleApplication2
{
    [InheritedExport]
    public interface ITest
    {
        void DoSomething();
    }

    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class Test : ITest
    {
        #region Implementation of ITest

        public void DoSomething()
        {
            Program.BackToProgram();
        }

        #endregion
    }

    [Export]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class TestClient
    {
        private readonly ITest m_test;

        [ImportingConstructor]
        public TestClient(ITest test)
        {
            m_test = test;
        }

        public void DoSomethingFromTestClient()
        {
            m_test.DoSomething();
        }
    }

    class Program
    {
        private static CompositionContainer m_container;

        static void Main()
        {
            m_container = new CompositionContainer(new TypeCatalog(typeof(Test), typeof(TestClient)), true);
            var testClient = m_container.GetExportedValue<TestClient>();
            testClient.DoSomethingFromTestClient();
        }

        public static void BackToProgram()
        {
        }
    }
}

现在让我们用NDepend 6.3来分析它.假设我想知道Program.BackToProgram的所有直接和间接调用者:
《c# – NDepend和Dependency Injection – 如何连接点?》

但是,类TestClient使用依赖注入通过ITest接口使用Test实例,因此寻找ITest.DoSomething的直接和间接调用者给了我:
《c# – NDepend和Dependency Injection – 如何连接点?》

所以,这给了我完整的图片 – Program.BackToProgram最终从Program.Main调用.

不幸的是,我不得不求助于手动代码检查以连接点.依赖注入似乎打破了NDepend跟踪调整DI边界内容的能力.

虽然这可以解释为DI严重依赖于反射并且反射并不真正适用于静态代码分析,但这仍然是一个大问题,因为我们的代码使用了相当多的DI.

那么,这个问题有什么解决方案吗?有没有办法配置NDepend来识别MEF实现的依赖注入?在一天结束时,当被问到Program.BackToProgram的所有直接和间接调用者时,我希望在没有人为干预的情况下在图上看到Program.Main.

也许有另一种工具可以做到这一点?

编辑1

Patrick from NDepend team提供的答案很有意思,但还不够好.实际上,它返回所涉及的方法,但是调用者图是断开的:
《c# – NDepend和Dependency Injection – 如何连接点?》

因此,对于这个人为的例子,可以推断出缺失的连接.但是这种奢侈品在广泛使用DI的生产代码中是不可用的.我们最终会得到很多不连贯的子图.这对跟踪呼叫者没有任何帮助.

最佳答案 您可以按原样应用
this question的答案.

// Retrieve the target method by name
let methodTarget = Methods.WithFullName("ConsoleApplication2.Program.BackToProgram()").Single()

// Build a ICodeMetric<IMethod,ushort> representing the depth of indirect
// call of the target method.
let indirectCallDepth = 
   methodTarget.ToEnumerable()
   .FillIterative(
       methods => methods.SelectMany(
          m => m.MethodsCallingMe.Union(m.OverriddensBase)))

from m in indirectCallDepth.DefinitionDomain
select new { m, callDepth = indirectCallDepth[m]  }

etvoilà:)

《c# – NDepend和Dependency Injection – 如何连接点?》

点赞