[英]C# generics: How to pass current class's type as a para
I would like to我想
modelBuilder.Entity<T>
without explicitly specifying the T. I would just like to say, the 'current class' (meaning in this example UserType
as it is UserType
on which the index needs creating)modelBuilder.Entity<T>
。我只想说“当前类”(在此示例中表示UserType
,因为它是需要在其上创建索引的UserType
)public class BaseLookupEntity : BaseEntity
{
[Key()]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public override int Id { get; set; }
//...
}
public class UserType: BaseLookupEntity
{
internal static void OnModelCreating(ModelBuilder modelBuilder)
{
// unique
modelBuilder.Entity<UserType>()
.HasIndex(c => c.Enum)
.IsUnique();
}
}
class someBaseClass
{
public void Foo<TInferrConcreteDerivedTypeCallingThisMethodHere>()
}
No, thats not possible, and if you understand how generics works you'd see why.不,那是不可能的,如果您了解 generics 的工作原理,您就会明白为什么。 Generic types are not resolved at runtime (excluding
dynamic
and reflection scenarios), all generic type parameters are resolved at compile time.泛型类型在运行时不解析(不包括
dynamic
和反射场景),所有泛型类型参数在编译时解析。 Therefore, there is no way the compiler can know what the real type of TInferrConcreteDerivedTypeCallingThisMethodHere
is from within SomeBaseClass
without running the code.因此,编译器无法在不运行代码的情况下从
SomeBaseClass
中知道TInferrConcreteDerivedTypeCallingThisMethodHere
的真实类型是什么。
Inheritance is a red herring here, the same issue arises with the classical example of statically unknown types: Inheritance 在这里是一个红鲱鱼,静态未知类型的经典示例也会出现同样的问题:
void Foo<T>(T t) { ... }
object o = GetSomeRuntimeObjectIDontKnowTheTypeOf();
Foo(o); T is inferred
Can you guess what T
is inferred to?你能猜出
T
的推断是什么吗? You can narrow it down to two options: Foo<RuntimeTypeOfUnkownObject>
or Foo<object>
?您可以将其缩小到两个选项:
Foo<RuntimeTypeOfUnkownObject>
或Foo<object>
? If you have doubts, run it and figure it out.如果您有疑问,请运行它并弄清楚。
Also, as far as type inference goes, a rule of the thumb, whenever you have a generic method with a signature similar to:此外,就类型推断而言,经验法则是,只要您有一个具有类似于以下签名的泛型方法:
void Foo<T>(/*no arguments from which T can be inferred*/)
or even甚至
T Foo<T>(/*no arguments from which T can be inferred*/)
T
can not or will not be inferred. T
不能或不会被推断。
You would want to make your base class generic as well in that case在这种情况下,您也想让您的基础 class 通用
public class BaseLookupEntity<T> : BaseEntity where T : BaseLookupEntity<T>
{
[Key()]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public override int Id { get; set; }
internal static void OnModelCreating(ModelBuilder modelBuilder)
{
// unique
modelBuilder.Entity<T>()
.HasIndex(c => c.Enum)
.IsUnique();
}
}
public class UserType: BaseLookupEntity<UserType>
{
}
There is in-built support for decoupled (from DB context) configurations.有对解耦(从数据库上下文)配置的内置支持。 Your configuration class must implement
IEntityTypeConfiguration<T>
interface .您的配置 class 必须实现
IEntityTypeConfiguration<T>
接口。
Then you can easily apply configurations inside your DbContext
's OnModelCreating
method using ApplyConfiguration<T>
method .然后,您可以使用
ApplyConfiguration<T>
方法轻松地在DbContext
的OnModelCreating
方法中应用配置。
Your example, could look like:您的示例可能如下所示:
public class CustomDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration<UserTypeConfiguration>(new UserTypeConfiguration());
}
}
public class UserTypeConfiguration : IEntityTypeConfiguration<UserType>
{
public void Configure(EntityTypeBuilder<UserType> builder)
{
builder
.HasIndex(c => c.Enum)
.IsUnique();
}
}
Note: I can't try your inheritance chain, but it should work out of the box, if you do:注意:我无法尝试您的 inheritance 链,但如果您这样做,它应该可以开箱即用:
Using generics, you can't.使用 generics,你不能。
Generics are evaluated at compile time, but as your base class will have multiple sub classes, the type will only be known at runtime. Generics 在编译时进行评估,但是由于您的基础 class 将有多个子类,因此该类型仅在运行时才知道。
There is an overload for ModelBuilder.Enity that accepts a System.Type object, which can be used at runtime, so you could use that in your base class. ModelBuilder.Enity有一个重载,它接受 System.Type object,可以在运行时使用,因此您可以在基础 class 中使用它。
Personally i would do this in your DbContext and list all the base classes individually eg我个人会在您的 DbContext 中执行此操作并单独列出所有基类,例如
private void MapLookupEntitity<TLookup>(DbModelBuilder modelBuilder) where TLookup : BaseLookupEntity
{
// unique
modelBuilder.Entity<TLookup>()
.HasIndex(c => c.Enum)
.IsUnique();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
MapLookupEntitity<UserType>(modelBuilder);
MapLookupEntitity<AnotherType>(modelBuilder);
// map some more..
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.