csf-dev / CSF.Reflection

MIT License
0 stars 0 forks source link

Create a service which gets collections of types #5

Closed craigfowler closed 5 years ago

craigfowler commented 6 years ago

This will become what I use to replace calls to the static typeof(SomeClass).Assembly.GetExportedTypes();.

I'd like to create an interface for a service which exposes a single method which returns an IEnumerable<Type>. A given solution may have many implementations, where each implementation should get a single classification of types which do not need further filtering or querying.

Rationale

I'd like to do this mainly for dependency injection registrations. In particular where I'm writing a registration which is essentially:

Register all concrete types which implement the interface IFoo, as themselves and as their implemented interfaces.

This could be used any other time I want to reflect a collection of types from one or more assemblies, which match a given specification though.

Example of planned usage

var fooTypes = new FooTypeProvider().GetTypes();
craigfowler commented 5 years ago

Here are my initial thoughts for this. It will need to take a dependency upon CSF.Specifications because of the need to create spec types which are used to test for available types.

These notes also contain some of the ideas for https://github.com/csf-dev/CSF.Reflection/issues/4

public interface IGetsTypes
{
    IEnumerable<Type> GetTypes();
}

public abstract class AssemblyTypeProvider : IGetsTypes
{
    public virtual IEnumerable<Type> GetTypes()
    {
        return GetType()
            .Assembly
            .GetExportedTypes();
    }
}

public class IsConcreteSpecification : SpecificationExpression<Type>
{
    public override GetExpression() => x => x.IsClass && !x.IsAbstract;
}

public class DerivesFromSpecification : SpecificationExpression<Type>
{
    readonly Type baseType;

    public override GetExpression()
        => x => baseType.IsAssignableFrom(x);

    public DerivesFromSpecification(Type baseType)
    {
        // TODO: Null check
        this.baseType = baseType;
    }
}

public class MyFunkyTypeProvider : IGetsTypes
{
    public IEnumerable<Type> GetTypes()
    {
        var assemblyOneTypes = new AssemblyOneTypeProvider().GetTypes();
        var assemblyTwoTypes = new AssemblyTwoTypeProvider().GetTypes();

        return assemblyOneTypes
            .Union(assemblyTwoTypes)
            .Where(new IsConcreteSpecification())
            .Where(new DerivesFromSpecification(typeof(IIsFunky)))
            .ToArray();
    }

}