反射列出返回类型,来自特定命名空间的C#应用​​程序中的参数

时间:2010-01-06 22:28:14

标签: c# api reflection assemblies

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

编辑由于我一直在使用MSTest对我的API进行单元测试,因此我添加了另一个单元测试来使用反射,如果暴露了旧API的任何部分,则会失败。但是,我遇到了反思问题。我在单元测试类中有using OldAPI然后使用

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

获取当前加载的所有程序集中的类型列表。然后,我迭代那些希望将类型列表削减到只有名称空间OldAPI中的类型。问题是命名空间OldAPI没有显示出来。我看到Microsoft.VisualStudio.TestTools,System.Reflection等命名空间,以及通过测试类中的using语句包含的其他命名空间,但没有“OldAPI”。这可能是因为旧API的COM内容,所以AppDomain.CurrentDomain.GetAssemblies()不包括程序集,即使它是通过类中的using语句包含的吗?

解决方案:我通过任意选择OldAPI中我知道的一个课程来完成必要的程序集,并执行以下操作,感谢SLaks'评论:

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

以下是我的单元测试的片段,用于检查我的API的任何类是否使用OldAPI的任何类,感谢SLaks'答案:

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 个答案:

答案 0 :(得分:1)

我不知道现有的工具,但这并不意味着您必须手动执行 - 您可以使用Reflection轻松编写自己的工具来执行此操作。基本上你只需要迭代Assembly.GetExportedTypes();对于每种类型,调用Type.GetMethods()和Type.GetProperties()并迭代结果;并转储每个公共方法或属性的返回和参数类型。

请注意,这样的手写工具需要运行已编译的程序集,而不是C#源代码。您可以执行与源代码类似的操作,但这取决于Visual Studio代码模型,这种代码模型使用起来相当困难,并且可能不值得像这样的一次性工作!

答案 1 :(得分:1)

您可以使用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递归。 (在这种情况下,你应该把它变成常规函数)