简体   繁体   English

通用虚拟方法和具体实现?

[英]Generic virtual method and concrete Implementation?

I'm currently working on a piece of code, where Generics are driving me crazy.我目前正在编写一段代码,其中 Generics 让我发疯。 Maybe somebody can point out the issue.也许有人可以指出这个问题。

All our DatabaseEntities have common Interfaces, one for example is IDatabaseEntityWithId .我们所有的DatabaseEntities都有通用接口,例如IDatabaseEntityWithId

let's say there is EntityA: IDatabaseEntityWithId .假设有EntityA: IDatabaseEntityWithId We have different, non-generic Forms / Controls.我们有不同的非通用 Forms / 控件。 We also have Controls that should be shared, and do their Job independent of the concrete Type.我们也有应该共享的控件,并且独立于具体类型来完成它们的工作。

Now, coming from Java this is quite easy there, cause every control could just use for example List<?> and pass / Process the list without actually caring what is inside.现在,来自 Java 这在那里非常容易,因为每个控件都可以只使用例如List<?>并传递/处理列表而不用真正关心里面的内容。

So, our Search-Control should also be able to "deal" with List<T> and IQueryable<T> without caring what T actually is.因此,我们的 Search-Control 也应该能够“处理” List<T>IQueryable<T>而无需关心T实际是什么。

The base implementation for an EntityList has the following methods, which our Search should utilize to generate the results, do pagination, etc. EntityList的基本实现具有以下方法,我们的搜索应该利用这些方法来生成结果、进行分页等。

public class EntityListControl{
  public virtual IQueryable<T> BaseQuery<T>(DBContext dbContext) where T : IDBEntityWithId => throw new NotImplementedException();
  public virtual List<string> AutocompleteSuggestionsQuickSearch() => throw new NotImplementedException();
  public virtual List<IDBEntityWithId> DoQuickSearch(string reference) => throw new NotImplementedException();
  public virtual IQueryable<T> DoTaggedSearchExtensions<T>(IQueryable<T> query, DbContext dbContext) where T : IDBEntityWithId  => throw new NotImplementedException();
}

The SearchControl has a reference to the currently loaded EntityListControl and basically should just act as orchestrator for the concrete methods, ie shortened it looks like: SearchControl有一个对当前加载的EntityListControl的引用,基本上应该充当具体方法的协调器,即缩短它看起来像:

class SearchControl{
   public void DoSearch(){
      String[] searchTags = this.SearchField.Text.Split(' ');
      using (DbContext db = DbContext.Factory()){
          var query = this.EntityListControl.BaseQuery<IDBEntityWithId>(db);
          
          //do other stuff.

          query = this.EntityListControl.DoTaggedSearchExtension<IDBEntityWithID>(query, db);
          
         //do other stuff

          List<IDBEntityWithId> result = query.Take(X).ToList();

         //do other stuff

          this.EntityListView.FactoryRows(result);
      }

You'll get the idea.你会明白的。

Now, for one of the EntityListControl -implementations, these methods might look like:现在,对于其中一个EntityListControl实现,这些方法可能如下所示:

public class EntityList: UserControl{
    ...
}
...

public class EntityListA : EntityList{

   public override IQueryable<EntityA> BaseQuery<EntityA>(DbContext db){
       return db.EntityA.Include("EntityB").Include("EntityC");
   }

   public IQueryable<EntityA> DoTaggedSearchExtension<EntityA>(IQueryable<EntityA> query, DbContext db){
      //Problem is now here...
      return query.Where(x => x.PropertyOfEntityA == true);
   }
}

The Problem is now in the concrete implementation of DoTaggedSearchExtension .问题现在出在DoTaggedSearchExtension的具体实现中。 Visual Studio here clearly lines out, that T is EntityA and the query is IQueryable<EntityA> - but refuses to accept any properties that don't belong to IDBEntityWithId . Visual Studio 在这里清楚地指出, TEntityA并且查询是IQueryable<EntityA> - 但拒绝接受不属于IDBEntityWithId的任何属性。 Why is that?这是为什么?

The error Message even reads "EntityA does not contain a definition for 'property'...." - which is wrong, it is there... IntelliSense just proposes properties of the common interface.错误消息甚至显示为“EntityA 不包含‘属性’的定义……”——这是错误的,它就在那里……IntelliSense 只是提出通用接口的属性。

Obviously in the generic EntityListControl , I can not be more concrete on the type of T , IBaseEntityWithId is one of the common interfaces I can ensure for all entities.显然,在通用的EntityListControl中,我不能更具体地说明T的类型, IBaseEntityWithId是我可以为所有实体确保的通用接口之一。

Ofc, I could leave away the whole generic-part and JUST work with interfaces, casting them to the actual type in the implementations, but that's not the point, isn't it? Ofc,我可以放弃整个通用部分,只使用接口,将它们转换为实现中的实际类型,但这不是重点,不是吗?

Any suggestion on how to fix this particular example?关于如何修复这个特定示例的任何建议?

You want the base class to be generic, not the methods!您希望基础 class 是通用的,而不是方法!

public class EntityList<T> where T : IDBEntityWithId
{
  public virtual IQueryable<T> BaseQuery(DBContext dbContext) => throw new NotImplementedException();
  public virtual List<string> AutocompleteSuggestionsQuickSearch() => throw new NotImplementedException();
  public virtual List<IDBEntityWithId> DoQuickSearch(string reference) => throw new NotImplementedException();
  public virtual IQueryable<T> DoTaggedSearchExtensions(IQueryable<T> query, DbContext dbContext) => throw new NotImplementedException();
}

When you then implement this, you get the concrete types you expect当你实现它时,你会得到你期望的具体类型

public class EntityListA : EntityList<EntityA>{

   public override IQueryable<EntityA> BaseQuery(DbContext db){
       return db.EntityA.Include("EntityB").Include("EntityC");
   }

   public IQueryable<EntityA> DoTaggedSearchExtension(IQueryable<EntityA> query, DbContext db){
      //Problem is now here... (Not any more it isnt!)
      return query.Where(x => x.PropertyOfEntityA == true);
   }
}

Live example for demo: https://do.netfiddle.net/SiICNV (Compiles fine but had to comment out the EF-specific stuff)现场演示示例: https://do.netfiddle.net/SiICNV (编译正常但必须注释掉特定于 EF 的内容)

The definition of DoTaggedSearchExtension identifies that T is a IDBEntityWithId DoTaggedSearchExtension 的定义标识 T 是一个 IDBEntityWithId

C# is strongly typed so it only allows methods defined on IDBEntityWithId C# 是强类型的,所以它只允许在 IDBEntityWithId 上定义的方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果具体实现中存在重载方法,则隐藏虚拟方法实现 - Hide virtual method implementation if overloaded method is present in concrete implementation 将具体实现作为通用返回 - Returning a concrete implementation as a generic 使用虚方法模拟具体类 - Mocking a concrete class with a virtual method 当将接口用作方法的通用参数时,如何访问具体接口实现的值 - How to access values of a concrete interface implementation, when using the interface as a generic parameter to a method 如何通过泛型类型获得接口的具体实现? - How to get the concrete implementation of an interface by the generic type? 在Designer中不能使用的通用表单的具体实现 - Concrete Implementation of Generic Form Not Working in Designer 如何使具体实施更加通用 - How to make concrete implementation more generic 通用实现,但构造函数参数取决于具体类 - Generic implementation, but constructor arguments depend on concrete class 获得带有通用参数的接口的具体实现 - Get Concrete Implementation of Interface with Generic Parameter 在Ninject中寻找通用接口的具体实现 - Finding a Concrete Implementation of a Generic Interface in Ninject
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM