Skip to content

Actual Type Names of Generic dependencies not visible in GetObjects and its dependency hierarchyΒ #369

@andreashoel

Description

@andreashoel

We want to fetch all types in our dependecies to assert them using Snapshot Testing.
This works fine with normal non-generic types.

Example Layer:

public static IObjectProvider<IType> NonGenericLayer => Types()
    .That()
    .ResideInNamespace("SSCS")
    .As("Sample Layer NonGeneric");

That Namespace includes the following Class:

public void RegisterServiceCollection()
{
    var impl = new Implementation();
    var impl2 = new SecondImplementation();
    var sc = new BlankServiceCollection();
    sc.AddSingleton(impl);
    sc.AddSingleton(impl2);
}

Now, this gives me both "Implementation" as well as "SecondImplementation" as types, which is totally fine.

Now, since we use DI with generics to add services to DI, I have the following Service Collection Registration:

public void RegisterServiceCollection()
{
    var sc = new BlankServiceCollection();
    sc.AddScoped<Implementation>();
    sc.AddScoped<SecondImplementation>();
}

And I now use that to get the same dependencies, as well as trying to step through the dependency graph to check if I missed anything, but the only thing I can find is the generic type name, in this case "TService"

Now, if I use Mono.Cecil to walk through the types under test and get their generic arguments, I get my result:

public IEnumerable<string> GetGenericType(System.Reflection.Assembly assembly, IEnumerable<string> types) {
    foreach (var type in AssemblyDefinition.ReadAssembly(assembly.Location).MainModule.Types.Where(x => types.Contains(x.FullName))) {
        foreach (var method in type.Methods.Where(m => m.HasBody)) {
            foreach (var instr in method.Body.Instructions) {
                if ((instr.OpCode == OpCodes.Call || instr.OpCode == OpCodes.Callvirt) && instr.Operand is GenericInstanceMethod genericMethod) {
                    foreach (var arg in genericMethod.GenericArguments) {
                        yield return arg.FullName;
                    }
                }
            }
        }
    }
}

I would prefer to have these dependencies without having to go through Cecil myself. Did I miss anything and this is possible in the current codebase?
If ArchUnit lacks that function, is it possible to add this?

I have a sample project to show the issue and the expectations for this issue if necessary

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugCategorizes issue or PR as related to a bug.triage/duplicateIndicates an issue is a duplicate of other open issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions