使用反射在程序集类型中查找接口<T>
Use Reflection to Find Interface<T> in Assembly Types
我不确定是不是尖括号导致了我的问题,但我无法在 Stack Overflow 答案中找到答案。如果已经有了,欢迎您为我指明正确的方向。
总而言之,我有一个接口,但无法通过反射找到它。让我们开始吧:
接口
interface ICrew
{
string Name { get; set; }
}
interface IDataService<T>
{
IEnumerable<T> GetItems();
}
类
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;
}
代码
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;
}
}
我不知道如何正确查询程序集类型以获得 IDataService<T>
。我的 Get
方法直到运行时才知道要请求什么类型,并且只有在编译时知道类型时才能使用尖括号内的泛型。任何人都可以帮助我弄清楚我应该在这里做什么才能通过反射获得 Get
到 return 正确的 class 存储库?
如评论中所述,必须使用 Type.MakeGenericType
方法在运行时创建所需的类型 IDataService<"T">
。您的 Get
方法可能如下所示:
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;
}
好的,这已经得到回答,但作为对那个答案的补充(我完全同意并且自己构建了这个项目,我意识到我的代码几乎完全匹配@thehennyy's),有这个:
就个人而言,与其询问特定接口是否“是根据 Type.GetInterfaces()
的接口之一”,我更愿意询问实现给定接口的类型.基本相同,但语义可能很重要。
所以我的代码是这样的:
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);
}
但是,如果我们使用泛型,我们可以做得更好并完全避免 closed/open 泛型业务:
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>();
}
我不确定是不是尖括号导致了我的问题,但我无法在 Stack Overflow 答案中找到答案。如果已经有了,欢迎您为我指明正确的方向。
总而言之,我有一个接口,但无法通过反射找到它。让我们开始吧:
接口
interface ICrew
{
string Name { get; set; }
}
interface IDataService<T>
{
IEnumerable<T> GetItems();
}
类
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;
}
代码
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;
}
}
我不知道如何正确查询程序集类型以获得 IDataService<T>
。我的 Get
方法直到运行时才知道要请求什么类型,并且只有在编译时知道类型时才能使用尖括号内的泛型。任何人都可以帮助我弄清楚我应该在这里做什么才能通过反射获得 Get
到 return 正确的 class 存储库?
如评论中所述,必须使用 Type.MakeGenericType
方法在运行时创建所需的类型 IDataService<"T">
。您的 Get
方法可能如下所示:
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;
}
好的,这已经得到回答,但作为对那个答案的补充(我完全同意并且自己构建了这个项目,我意识到我的代码几乎完全匹配@thehennyy's),有这个:
就个人而言,与其询问特定接口是否“是根据 Type.GetInterfaces()
的接口之一”,我更愿意询问实现给定接口的类型.基本相同,但语义可能很重要。
所以我的代码是这样的:
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);
}
但是,如果我们使用泛型,我们可以做得更好并完全避免 closed/open 泛型业务:
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>();
}