简体   繁体   English

如何指向泛型抽象类?

[英]How to point to generic abstract class?

I haven't got problems with code since my last problem with interface covariance. 自从我上一个关于接口协方差的问题以来,我就没有代码问题。 Today I took another approach to the OLGAtherer architecture and I found huge (for me) obstacle. 今天,我对OLGAtherer架构采用了另一种方法,发现了巨大的障碍(对我而言)。 I hope that its huge only for me and I will find answer here :) OK, please check this out: 我希望它只对我有用,我会在这里找到答案:)好的,请检查一下:

I have abstract generic class: 我有抽象的泛型类:

abstract class Repository<T> where T : Entity

this class contain signatures of four CRUD methods (add, insert, etc.) and two protected fields. 此类包含四个CRUD方法(添加,插入等)和两个受保护字段的签名。 Any repository that I will create must inherit from this superclass. 我将创建的任何存储库都必须继承此超类。 I have repositories like, for example: 我有类似的存储库:

class BookRepository : Repository<Book>

Now I have class DB that is responsible for operations on DB file. 现在,我有了负责对DB文件进行操作的类DB。 And there is my problem. 还有我的问题。 Look at this method placed in DB class: 查看放置在DB类中的此方法:

    void Add(List<Entity> enitites, Type entityType)
    {
       Repository<entityType> repo = EntitiesFactory(entityType);
       repo.Add(entities);
    }

I know that above method won't work, but this visualize my problem (hopefully) - I would like to dynamically create repository of the specified type, but I have no idea how to do this. 我知道上面的方法不起作用,但是(希望)可以直观地看到我的问题-我想动态创建指定类型的存储库,但是我不知道该怎么做。 This has been always my main OOP problem - I could code inheritance (or implementation of interfaces) but I could not use these inherited classes. 这一直是我的主要OOP问题-我可以编码继承(或接口的实现),但不能使用这些继承的类。 Please clarify this to me. 请向我澄清一下。 Thank you in advance. 先感谢您。

Paweł Paweł


I used hints that you provided and this is what I have now: 我使用了您提供的提示,这就是我现在所拥有的:

public void Add<T>(List<T> entities, string repoName) where T : Entity
{
   Repository<T> repo = RepoFactory<T>(repoName, typeof(T));
   repo.Add(entities);
}

private Repository<T> RepoFactory<T>(string repoName, Type t) where T : Entity
{
   if (t == typeof(Book))
   {
   Repository<T> repo = (Repository<T>)((object)(new BookRepository(this.ConnectionString, repoName)));
   }

   return null;

} }

RepoFactory is now in DB class (which is, by the way, some sort of Bridge here) - it should be moved elsewhere probably, but it's not a main problem here. RepoFactory现在在DB类中(顺便说一下,这里是某种Bridge)-可能应该将其移到其他地方,但这不是主要问题。

First, I don't know whether RepoFactory body is implemented in the proper way - I guess not. 首先,我不知道RepoFactory主体是否以正确的方式实现-我想不是。

Second - I assume that I will call DB methods from other class (let's say - WindowsForm, for simplicity). 其次-我假设我将从其他类中调用数据库方法(为简单起见,假设为WindowsForm)。 I will call Add with parameter T dependent on user's choice. 我将根据用户的选择使用参数T调用Add。 This is situation that I have problem and fix it temporarily, because now DB is OK, but if I would have to implement WindowsForm code, I will encounter it another time (I think) - in the future I will try to figure out answer to the same question, but on the higher level (above DB) - I hope you understand me... I basically mean, that I will not know how to dynamically call Add method, because T will be dependent on user's choice (OLGAtherer has to be Repository Manager that would support Books and other kind of collections). 这是我遇到的问题,需要临时解决,因为现在DB可以了,但是如果我必须实现WindowsForm代码,我会再遇到一次(我认为)-将来我将尝试找出答案。同样的问题,但在更高级别(数据库之上)-我希望您理解我...我的基本意思是,我不知道如何动态调用Add方法,因为T将取决于用户的选择(OLGAtherer必须是将支持“书籍”和其他类型收藏的“存储库管理器”。 And if user will try to work with his book collection, I will have to call Add() method. 如果用户尝试使用他的藏书,则必须调用Add()方法。 If with Comics collection, Add(). 如果带有Comics集合,则添加()。 I don't want to write class above for each kind of collection, but rather use one call of Add to do this. 我不想为每种类型的集合编写上面的类,而是使用一个Add调用来做到这一点。

If you understand what I mean, you're really good :) My English sucks, but I'm working on it. 如果您理解我的意思,那么您真的很好:)我的英语很烂,但是我正在努力。 Thank you for previous answers and thanks in advance for further ones. 感谢您之前的回答,并预先感谢您进一步的回答。 Paweł Paweł

I'm not quite sure what you want. 我不太确定你想要什么。 Will this do? 这样可以吗?

void Add<T>(List<T> entities) where T : Entity
{
   Repository<T> repo = EntitiesFactory(typeof(T));
   repo.Add(entities);
}

Also, I suggest that you be as flexible as possible with input parameters, eg use IEnumerable<T> instead of List<T> for this method and also in the Repository<T>.Add() method. 另外,我建议您在输入参数方面尽可能地灵活,例如,对于此方法以及在Repository<T>.Add()方法中,请使用IEnumerable<T>代替List<T> You might want to pass in a lazily-evaluated query, or chain multiple LINQ methods together. 您可能想要传递惰性计算的查询,或将多个LINQ方法链接在一起。

You can make the Add method generic. 您可以使Add方法通用。

void Add<T>(List<T> enitites)
{
   Repository<T> repo = EntitiesFactory(typeof(T));
   repo.Add(entities);
}

You can make it type-safe by modifying your object hiearchy with one more layer of indirection as follows: 您可以按如下所示通过一层间接层来修改对象层次结构,从而使其具有类型安全性:

public abstract class EntityCollection<T> : List<T>
    where T : Entity
{
    public abstract Repository<T> GetRepository();
}

public class BookCollection : EntityCollection<Book>
{
    public override Repository<Book> GetRepository()
    {
        return BookRepository();
    }
}

So now you can modify your DB class as follows: 因此,现在您可以按以下方式修改数据库类:

public void Add<T>(EntityCollection<T> entities)
{
    Repository<T> repo = entities.GetRepository();
    repo.Add(entities);
}

So now you can pass an instance of BookCollection into your Add method and it will work in a 100% type-safe, transparent manner. 因此,现在您可以将BookCollection的实例BookCollection到您的Add方法中,它将以100%类型安全,透明的方式工作。

Just to add to everyone else's answers, you may want to take a look at the Inversion of Control (IoC) design pattern as well. 只是为了增加其他所有人的答案,您可能还想看看控制反转(IoC)设计模式。 It may simplify your life in future work. 它可以简化您将来的工作。

With dependency injection, which is what IoC gives you, you can significantly simplify your use of the EntitiesFactory, for example. 例如,借助IoC为您提供的依赖项注入,您可以大大简化EntitiesFactory的使用。

I'm using StructureMap at the moment to implement IoC and it's working well for me. 我目前正在使用StructureMap来实现IoC,它对我来说运作良好。

Here's Martin Fowler's page on IoC, and Wikipedia's , to get you started. 这是有关IoC的Martin FowlerWikipedia 页面,以帮助您入门。

Whatever you are returning in EntitiesFactory() is what you need to use. 您在EntitiesFactory()中返回的内容都是您需要使用的。 So the problem is really with code which you have not shown. 因此,问题实际上出在您未显示的代码上。 Show the code for EntitiesFactory() and we get a better idea on what you are trying to accomplish. 显示EntitiesFactory()的代码,我们会更好地了解您要完成的工作。

NOTE: You understand that you cannot overload return types (unfortunately). 注意:您了解,您不能重载返回类型(不幸的是)。

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

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