Skip to main content
added 1035 characters in body
Source Link
Flater
  • 5.5k
  • 18
  • 23

Which in turn leads to being able to refactor the initial code:

var type = typeof(IUnmapped);

builder
    .RegisterAssemblyTypes(targetAssembly)
    .Where(x => !type.IsAssignableFrom(x))
    .As(type => 
        type.GetInterfaces()
            .Where(interfacetype => 
                   interfacetype.IsAssignableFrom(typeof(ICommandHandler<>))
                   || interfacetype.IsAssignableFrom(typeof(IEventHandler<>))))
    .AsSelf()
    .InstancePerDependency();
var type = typeof(IMapped);var skippedTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes()).Where(p =>!type.IsAssignableFrom(p));
var type = typeof(IMapped);
var skippedTypes = AppDomain.CurrentDomain
                            .GetAssemblies()
                            .SelectMany(s => s.GetTypes())
                            .Where(p => !type.IsAssignableFrom(p));

Or when refactoring the old code:

var type = typeof(IMapped);

builder
    .RegisterAssemblyTypes(targetAssembly)
    .Where(x => type.IsAssignableFrom(x))
    .As(type => 
        type.GetInterfaces()
            .Where(interfacetype => 
                   interfacetype.IsAssignableFrom(typeof(ICommandHandler<>))
                   || interfacetype.IsAssignableFrom(typeof(IEventHandler<>))))
    .AsSelf()
    .InstancePerDependency();
var skippedTypes = AppDomain.CurrentDomain
                            .GetAssemblies()
                            .SelectMany(s => s.GetTypes())
                            .Where(p => !p.GetConstructors().Length == 0Any());
var type = typeof(IMapped);var skippedTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes()).Where(p =>!type.IsAssignableFrom(p));
var skippedTypes = AppDomain.CurrentDomain
                            .GetAssemblies()
                            .SelectMany(s => s.GetTypes())
                            .Where(p => p.GetConstructors().Length == 0);

Which in turn leads to being able to refactor the initial code:

var type = typeof(IUnmapped);

builder
    .RegisterAssemblyTypes(targetAssembly)
    .Where(x => !type.IsAssignableFrom(x))
    .As(type => 
        type.GetInterfaces()
            .Where(interfacetype => 
                   interfacetype.IsAssignableFrom(typeof(ICommandHandler<>))
                   || interfacetype.IsAssignableFrom(typeof(IEventHandler<>))))
    .AsSelf()
    .InstancePerDependency();
var type = typeof(IMapped);
var skippedTypes = AppDomain.CurrentDomain
                            .GetAssemblies()
                            .SelectMany(s => s.GetTypes())
                            .Where(p => !type.IsAssignableFrom(p));

Or when refactoring the old code:

var type = typeof(IMapped);

builder
    .RegisterAssemblyTypes(targetAssembly)
    .Where(x => type.IsAssignableFrom(x))
    .As(type => 
        type.GetInterfaces()
            .Where(interfacetype => 
                   interfacetype.IsAssignableFrom(typeof(ICommandHandler<>))
                   || interfacetype.IsAssignableFrom(typeof(IEventHandler<>))))
    .AsSelf()
    .InstancePerDependency();
var skippedTypes = AppDomain.CurrentDomain
                            .GetAssemblies()
                            .SelectMany(s => s.GetTypes())
                            .Where(p => !p.GetConstructors().Any());
Source Link
Flater
  • 5.5k
  • 18
  • 23

Generally speaking, classes with private-only constructors are irrelevant in terms of DI. It makes no sense to include them in your container because the container can't do anything with them.

The only exception here is when you register the specific instance of a type with the container, which only really makes sense in scope of a singleton, e.g. something like:

builder.Register(c => User.Instance).As<User>().SingleInstance();

However, since you are clearly dealing with multiple of these classes, and you're trying to iteratively handle these, this custom-tailored-per-type approach seems out of scope for your intentions.

The question all boils down to "How do I find all of these types that I don't want to register?", which for your case means filling in _skippedTypes without needing to manually write down each class.

The easiest way to do so is to use a marker interface and reflection.

A marker interface is an empty interface:

public interface IUnmapped {}

Which your intended classes then implement:

public class User : IUnmapped
{
    // ...
}

And then you can use reflection to find all of the types that implement this interface:

var type = typeof(IUnmapped);
var skippedTypes = AppDomain.CurrentDomain
                            .GetAssemblies()
                            .SelectMany(s => s.GetTypes())
                            .Where(p => type.IsAssignableFrom(p));

Some further notes:

  • When using marker interfaces, I'd be more inclined to use a positive marker, i.e. IMapped to indicate the types that you do want to add to the container. The only difference in your reflection logic is inverting the Where:
var type = typeof(IMapped); var skippedTypes = AppDomain.CurrentDomain .GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => !type.IsAssignableFrom(p));
  • You can cut out the middle man marker interface, and use reflection to look up each type's public constructors, and then pick the ones that don't have any. However, I am unsure how much of a performance hit this might entail.
var skippedTypes = AppDomain.CurrentDomain
                            .GetAssemblies()
                            .SelectMany(s => s.GetTypes())
                            .Where(p => p.GetConstructors().Length == 0);

I think I'd still prefer the marker interface, even though I generally dislikee marker interfaces, simply because it means you're able to also skip a type that has a public constructor when there is an ulterior reason to want to skip it.