[英]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 在这里清楚地指出, T
是EntityA
并且查询是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.