[英]How to pass an string as a type parameter for a generic DbSet in Entity Framework?
Consider the following sample code, What's the most concise way to pass C# generic type as a parameter? 考虑以下示例代码,将C#泛型类型作为参数传递的最简洁方法是什么?
public dynamic MyDbSet(string typeName)
{
var typeofDbSet = typeof(DbSet<>);
Type[] typeArgs = { Type.GetType(typeName) };
var type = typeofDbSet.MakeGenericType(typeArgs);
dynamic dbsetOfT = Activator.CreateInstance(type);
return dbsetOfT;
//Call it
//var notificationTypes = MyDbSet("NotificationType");
//var list = notificationTypes.ToList();
}
Or something like this: 或类似这样的东西:
public dynamic MyDbSet2(string typeName)
{
var keyValuePairs = new Dictionary<string, dynamic>
{
{nameof(NotificationType), Set<NotificationType>().AsQueryable()}
};
return keyValuePairs[typeName];
//Call it
//var notificationTypes = MyDbSet2("NotificationType");
//var list = notificationTypes.ToList();
}
Activator.CreateInstance(type)
would fail since DbSet
has no public parameterless constructor. Activator.CreateInstance(type)
将失败,因为DbSet
没有公共的无参数构造函数。
Unless you really need to pass the type name as string, the best way to do this is creating a generic function, getting the constructor and invoking it. 除非您确实需要将类型名称作为字符串传递,否则执行此操作的最佳方法是创建泛型函数,获取构造函数并调用它。 It would something like this: 会是这样的:
public DbSet<T> MyDbSet<T>() where T : class
{
return (DbSet<T>)typeof(DbSet<T>).GetConstructor(BindingFlags.NonPublic |
BindingFlags.Instance, null, Type.EmptyTypes, null).Invoke(null);
}
Then, you would call it by MyDbSet<NotificationType>()
然后,您可以通过MyDbSet<NotificationType>()
调用
Update: 更新:
Since passing the name is required, you can do this: 由于需要传递名称,因此您可以执行以下操作:
public dynamic MyDbSet(string typeName)
{
return typeof(DbSet<>).MakeGenericType(Type.GetType(typeName)).
GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,
null, Type.EmptyTypes, null).Invoke(null);
}
Then, you would call it by MyDbSet("<namespace>.NotificationType")
. 然后,可以通过MyDbSet("<namespace>.NotificationType")
调用。 Specifying the namespace is required since otherwise Type.GetType
wouldn't find the type and return null
指定名称空间是必需的,因为否则Type.GetType
将找不到类型并返回null
Try this extension code: 尝试以下扩展代码:
//Use var list = _context.MyDbSet("ConsoleAppEF.Student").ToList();
public static IQueryable MySet(this SchoolContext context, string typeName)
{
var T = Type.GetType(typeName);
// Get the generic type definition
MethodInfo method = typeof(SchoolContext)
.GetMethod("MySet", BindingFlags.Public | BindingFlags.Instance);
// Build a method with the specific type argument you're interested in
method = method.MakeGenericMethod(T);
return method.Invoke(context, null) as IQueryable;
}
public static IQueryable<T> Set<T>(this SchoolContext context)
{
// Get the generic type definition
MethodInfo method = typeof(SchoolContext)
.GetMethod(nameof(SchoolContext.Set), BindingFlags.Public | BindingFlags.Instance);
// Build a method with the specific type argument you're interested in
method = method.MakeGenericMethod(typeof(T));
return method.Invoke(context, null) as IQueryable<T>;
}
public static IList ToList1(this IQueryable query)
{
var genericToList = typeof(Enumerable).GetMethod("ToList")
.MakeGenericMethod(new Type[] { query.ElementType });
return (IList)genericToList.Invoke(null, new[] { query });
}
Sample DbContext: 样本DbContext:
public class SchoolContext : DbContext
{
public SchoolContext() : base("SchoolContext")
{
}
public DbSet<Student> Students { get; set; }
public virtual new DbSet<TEntity> MySet<TEntity>() where TEntity : BaseEntity
{
return base.Set<TEntity>();
}
}
Sample Entity: 样本实体:
public class Student : BaseEntity
{
public string LastName { get; set; }
public string FirstMidName { get; set; }
}
public class BaseEntity
{
public int Id { get; set; }
}
Use it: 用它:
class Program
{
static void Main(string[] args)
{
Seed();
var _context = new SchoolContext();
var list = _context.MySet("ConsoleAppEF.Student").ToList1();
}
private static void Seed()
{
var _context = new SchoolContext();
var students = new List<Student>
{
new Student{FirstMidName="Carson",LastName="Alexander"},
};
students.ForEach(s => _context.Students.Add(s));
_context.SaveChanges();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.