Reputation: 320
I'm not sure if it's the angle brackets that are causing me problems, but I'm having trouble coming up with an answer within the Stack Overflow answers. If there's one already out there, I'd welcome you to point me in the right direction.
To summarize, I have an Interface and I can't get reflection to find it. Let's set the stage:
Interfaces
interface ICrew
{
string Name { get; set; }
}
interface IDataService<T>
{
IEnumerable<T> GetItems();
}
Classes
class Crew : ICrew
{
public string Name { get; set; }
}
class CrewRepository : IDataService<ICrew>
{
DbContext _context { get; }
public CrewRepository(DbContext context)
{
_context = context;
}
public IEnumerable<ICrew> GetItems()
{
return _context.Crews;
}
}
class DbContext
{
public DbContext()
{
Crews = new List<Crew>();
}
public List<Crew> Crews;
}
Code
class Program
{
private static DbContext _context;
static void Main(string[] args)
{
_context = new DbContext();
//I want to find CrewRepository (which is type of IDataService<ICrew>)
var dataService = Get(typeof(ICrew));
}
private static object Get(Type T)
{
var types = typeof(CrewRepository).Assembly.GetTypes();
var test = types.Where(t => t.IsAssignableFrom(T)); //Finds ICrew
var test2 = types.Where(t => t.GetInterfaces().Contains(T)); //Finds Crew
var test3 = types.Where(t => t.GetInterfaces().Contains(typeof(IDataService<>))); //Finds nothing
var test4 = types.Where(t => t.IsAssignableFrom(typeof(IDataService<>))); //Finds interface IDataService
var test5 = types.Where(t => typeof(IDataService<>).IsAssignableFrom(t)); //Finds interface IDataService
var instance = types
.Where(t => t.IsAssignableFrom(T))
.FirstOrDefault();
if (instance != null)
{
return Activator.CreateInstance(instance, _context);
}
return default;
}
}
I can't figure out how to query the Assembly Types correctly to get IDataService<T>
. My Get
method doesn't know what type it's going to be asked for until runtime, and generics inside of angle brackets are only able to be used if I know the type at compile time. Can anyone help me figure out what I should be doing here to get Get
to return the correct class Repository that I'm hoping for by using reflection?
Upvotes: 1
Views: 752
Reputation: 42125
Okay this has already been answered, but just as an addition to that answer (which I agree with entirely and having built this project out myself, I realise my code almost exactly matches @thehennyy's), there is this:
Personally, rather than asking if a particular interface "is one of the interfaces according to Type.GetInterfaces()
", I just prefer to ask for types that implement a given interface. It's basically the same, but the semantics can be important.
So my code looks like this:
private static object Get2(Type t)
{
// Create the closed generic type that we need
var closedType = typeof(IDataService<>).MakeGenericType(t);
var allTypes = typeof(CrewRepository).Assembly.GetTypes();
var dataServiceType = allTypes.Single(x => closedType.IsAssignableFrom(x));
return Activator.CreateInstance(dataServiceType, _context);
}
However if we're using generics, we can do better and avoid that closed/open generic type business entirely:
private static IDataService<T> Get3<T>()
{
var allTypes = typeof(CrewRepository).Assembly.GetTypes();
var dataServiceType = allTypes.Single(x => typeof(IDataService<T>).IsAssignableFrom(x));
return (IDataService<T>)Activator.CreateInstance(dataServiceType, _context);
}
static void Main(string[] args)
{
_context = new DbContext();
//I want to find CrewRepository (which is type of IDataService<ICrew>)
var dataService3 = Get3<ICrew>();
}
Upvotes: 0
Reputation: 4218
As mentioned in the comments, have to use the Type.MakeGenericType
method to create the needed type IDataService<"T">
at runtime. Your Get
method could look like this:
private static object Get(Type t)
{
var types = typeof(CrewRepository).Assembly.GetTypes();
var runtimeType = typeof(IDataService<>).MakeGenericType(t);
var type = types.SingleOrDefault(x => x.GetInterfaces().Contains(runtimeType));
if (type != null)
{
return Activator.CreateInstance(type, _context);
}
return null;
}
Demo: https://dotnetfiddle.net/vRJzr8
Upvotes: 3