简体   繁体   English

C# generics:如何将当前类的类型作为参数传递

[英]C# generics: How to pass current class's type as a para

I would like to我想

  1. Move my OnModelCreating to the base class and将我的 OnModelCreating 移动到基础 class 和
  2. Call 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)在不明确指定 T 的情况下调用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> 方法轻松地在DbContextOnModelCreating方法中应用配置。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM