Reputation: 10479
I've got two types of repository classes in my API:
Those with both IRepository and IReportRepository:
internal class BuildingRepository : IBuildingRepository
public interface IBuildingRepository : IRepository<Building>, IReportRepository<BuildingReport>
And those with just IRepository:
internal class AppointmentRepository : IAppointmentRepository
public interface IAppointmentRepository : IRepository<Appointment>
How can I return all repositories that only implement IRepository and not IReportRepository. I thought it would be something like this:
var repoInterfaceType = typeof(IRepository<>);
var reportRepo = typeof(IReportRepository<>);
var repoTypes = asm.GetTypes().Where(x =>
!x.IsInterface && !x.IsAbstract && x.IsClass &&
!x.IsGenericType && x.GetInterfaces().Any(y =>
y.IsGenericType &&
repoInterfaceType.IsAssignableFrom(y.GetGenericTypeDefinition()) &&
!reportRepo.IsAssignableFrom(y.GetGenericTypeDefinition()))).ToList();
But it is still returning me both. What am I missing?
Upvotes: 1
Views: 69
Reputation: 52250
You can greatly shorten the code using GetInterface(string):
var results = asm.GetTypes()
.Where
(
t => t.GetInterface("IRepository`1") != null
&& t.GetInterface("IReportRepository`1") == null
);
This LINQ will iterate over all types and attempt to retrieve the two interfaces of interest. If the interface can't be found, only null will be returned, so we just need to check that the right one is null and the other one isn't.
In case you are wondering where I got the string "IReportRepository`1", this is known as the mangled name, which is the string the CLR uses internally (you may recognize it from stack dumps). If you don't feel comfortable using a string literal, you can get it at runtime from the type's Name property, e.g.
var mangledName = typeof(IReportRepository<>).Name;
Upvotes: 1
Reputation: 2009
Your .Any(y =>
y.IsGenericType &&
repoInterfaceType.IsAssignableFrom(y.GetGenericTypeDefinition()) &&
!reportRepo.IsAssignableFrom(y.GetGenericTypeDefinition()))
parts must be split two queries. Because, BuildingRepository
class is implementation of IRepository<Building>
. This interface is assignable from IRepository<>
and not assignable from IReport<>
interface. Your Any
condition return true in this case.
Your Linq can be modified like:
var repoTypes = asm.GetTypes().Where(x =>
!x.IsInterface && !x.IsAbstract && x.IsClass &&
!x.IsGenericType &&
x.GetInterfaces().All(y => !y.IsGenericType || !reportRepo.IsAssignableFrom(y.GetGenericTypeDefinition())) &&
x.GetInterfaces().Any(y => y.IsGenericType &&
repoInterfaceType.IsAssignableFrom(y.GetGenericTypeDefinition())))
.ToList();
Upvotes: 1