I’ve been working on an API that encapsulates another, trickier-to-use API. The goal is for my API to not require the user to touch any of the old API by 1) not requiring any parameters of classes in the old API and 2) not returning any instances of classes in the old API. Is there a program, perhaps a Visual Studio plugin, that can analyze my C# solution and give me a list of all the return types from publicly accessible methods in publicly accessible classes, as well as all the parameter types in such methods? Otherwise it seems like I’ll have to manually go through all my classes and see if any of the old API is exposed to the user.
Edit: Since I’ve been using MSTest for unit testing my API anyway, I added another unit test to use reflection and Fail if any parts of the old API are exposed. However, I’m stuck with a reflection problem. I have using OldAPI in the unit test class and then I use
AppDomain.CurrentDomain.GetAssemblies().SelectMany(
assembly => assembly.GetTypes()
)
to get a list of the types in all the assemblies currently loaded. I then iterate over those in hopes of paring down the list of types to only those in the namespace OldAPI. The problem is that the namespace OldAPI does not show up. I see namespaces like Microsoft.VisualStudio.TestTools, System.Reflection, and others that are included via using statements in the test class, but no “OldAPI”. Could this be because of COM stuff with the old API, so AppDomain.CurrentDomain.GetAssemblies() doesn’t include the assembly even though it’s included via a using statement in the class?
Solution: I got the necessary assembly by arbitrarily choosing one class I know is in OldAPI and doing the following, thanks to SLaks‘ comment:
Func<Type, bool> isBad = t => t.Assembly == typeof(OldAPI.SomeClass).Assembly;
Here’s a snippet of my unit test for checking if any of my API’s classes use any of OldAPI‘s classes, thanks to SLaks‘ answer:
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));
You can use LINQ, like this:
This would be easiest to do in LINQPad.
Note that this doesn’t traverse generic types, so it’ll ignore a
List<BadType>.You should probably make
isBadrecursive. (In which case you should turn it into a regular function)