代码之家  ›  专栏  ›  技术社区  ›  Sarah Vessels

从特定命名空间反射到列出返回类型、C应用程序中的参数

  •  1
  • Sarah Vessels  · 技术社区  · 15 年前

    我一直在研究一个封装另一个更复杂的API的API。我的API的目标是在1)不需要旧API中类的任何参数,2)不返回旧API中类的任何实例之前,不要求用户触摸任何旧API。有没有一个程序,也许是一个Visual Studio插件,可以分析我的C解决方案,并给我一个列表,列出公共可访问类中公共可访问方法的所有返回类型,以及此类方法中的所有参数类型?否则,我似乎必须手动地浏览所有类,看看是否有任何旧的API向用户公开。

    编辑: 由于我一直在使用MSTEST对我的API进行单元测试,所以我添加了另一个单元测试来使用反射,如果旧API的任何部分暴露出来,则会失败。但是,我一直在思考一个问题。我有 using OldAPI 在单元测试课上,然后我用

    AppDomain.CurrentDomain.GetAssemblies().SelectMany(
        assembly => assembly.GetTypes()
    )
    

    获取当前加载的所有程序集中的类型列表。然后,我对这些类型进行迭代,希望将类型列表缩减为名称空间中的类型列表。 OldAPI . 问题是命名空间 奥尔达皮 不会出现。我看到了诸如Microsoft.VisualStudio.TestTools、System.Reflection等名称空间,以及通过 using 测试类中的语句,但没有“oldapi”。这可能是因为旧API的COM特性,所以 AppDomain.CurrentDomain.GetAssemblies() 不包括程序集,即使它通过 使用 课堂陈述?

    解决方案: 我随意选择了一门我知道的课,得到了必要的集合。 奥尔达皮 并做以下工作,多亏了 SLaks 评论:

    Func<Type, bool> isBad = t => t.Assembly == typeof(OldAPI.SomeClass).Assembly;
    

    下面是我的单元测试的一个片段,用于检查我的任何API类是否使用 奥尔达皮 多亏了 消化系统 回答:

    MethodInfo[] badMethods = methods.Where(
        m => (
                 isBad(m.ReturnType) ||
                 m.GetParameters().Any(p => isBad(p.ParameterType))
             ) && !isBad(m.DeclaringType)
    ).ToArray();
    string[] badMethodNames = badMethods.Select(
        m => m.DeclaringType.Name + "." + m.Name
    ).Distinct().ToArray();
    Assert.AreEqual(0, badMethodNames.Length, "Some methods in " +
        monitoredNamespaces + " projects expose OldAPI: " +
        string.Join(", ", badMethodNames));
    
    2 回复  |  直到 15 年前
        1
  •  1
  •   SLaks    15 年前

    您可以使用Linq,如下所示:

    Func<Type, bool> isBad = t => t.Assembly == badAssembly;
    
    var types = yourAssembly.GetTypes();
    var methods = types.SelectMany(t => t.GetMethods()).ToArray();
    
    var badMethods = methods.Where(m => isBad(m.ReturnType) 
        || m.GetParameters().Any(p => isBad(p.ParameterType);
    
    var properties = types.SelectMany(t => t.GetProperties()).ToArray();
    var badProperties = properties.Where(p => isBad(p.PropertyType));
    

    这是最容易做到的 LINQPad .

    注意,这不会遍历泛型类型,因此它将忽略 List<BadType> .
    你应该做 isBad 递归的。(在这种情况下,您应该将其转换为常规函数)

        2
  •  1
  •   itowlson    15 年前

    我不知道这方面的现有工具,但这并不意味着您必须手动完成这项工作——您可以非常容易地使用反射编写自己的工具来完成这项工作。基本上,您只需要在assembly.getexportedtypes()上迭代;对于每个类型,调用type.getmethods()和type.getproperties()并迭代结果;以及为每个公共方法或属性转储返回和参数类型。

    请注意,这样的手写工具需要运行编译的程序集,而不是C源代码。您可以做一些类似于源代码的事情,但这取决于Visual Studio代码模型,该模型比较难使用,可能不值得为此一次性付出努力!