具有泛型继承的隐式引用转换错误

问题描述 投票:0回答:2

我的应用程序中具有以下类集:

这代表一个实体,它是一个SQL表。每个实体类都从该接口继承。

public interface IBaseEntity
{
     public int Id { get; set; }
}

然后,我有一个类,其中包含该实体的所有业务逻辑。 BaseBLL保留所有业务对象通用的方法。

public class BLLPai<D>
        where D : class
{
        protected D EntidadeData;
}
public class BaseBLL<E, D> : BLLPai<D>
        where E: IBaseEntity
        where D: BaseData<E>
{
     //commom methods
}

要为实体创建业务对象,还需要创建一个Data对象,该对象将保存所有与数据库有关的命令。

 public class BaseData<E> : DataPai
        where E : IBaseEntity
{
     // commom methods
}

public class DataPai
{
    protected DbConnection dbCon { get; set; }
     public DataPai()
    {
        dbCon = new DbConnection();
    }
}

这将是此设计中的工作实体(数据库表)的示例:

public class MyTable : IBaseEntity
{
    public int Id {get;set;}
    public string Name {get;set;}
}
public MyTableData: BaseData<MyTable>
{
    public List<MyTable> GetAllItems()
    {
        // return result of SELECT
    }
}
public MyTableBLL : BaseBLL<MyTable, MyTableData>
{
    public List<MyTable> GetAllItems()
    {
         // business logic
         return this.EntidadeData.GetAllItems();
    }
}

为了在我的体系结构中使用它,我设计了一个Controller基类,我在所有Controller中都使用了该基类。 (我正在WebApi .Net Core项目中使用此功能)该类如下:

public class MyTableController : GerenciadorLogadaCadastroController<MyTable, MyTableBLL>
{
}

[ApiController]
public abstract class GerenciadorLogadaCadastroController<Entidade, BLL> : ControllerBase
        where Entidade : IBaseEntity
        where BLL : BaseBLL<Entidade, BaseData<Entidade>>
{
}

我不理解的是为什么当我尝试创建MyTableController类时它给我一个错误:

错误:

类型'MyTableBLL'不能用作类型参数'BLL'通用类型或方法'GerenciadorLogadaCadastroController<Entidade,BLL>'。没有从'MyTableBLL'到''BaseBLL<MyTable, BaseData<MyTable>>'。

但是,如果我将GerenciadorLogadaCadastroController和MyTableController更改为此,它似乎可以正常工作。

public abstract class GerenciadorLogadaCadastroController<Entidade, BLL, Data> : ControllerBase
        where Entidade : IBaseEntity
        where BLL : BaseBLL<Entidade, Data>
        where Data: BaseData<Entidade>
{
}

public class MyTableController : GerenciadorLogadaCadastroController<MyTable, MyTableBLL, MyTableData>
{
}

但是我不想键入Data类,因为它已经包含在BLL类中。我在Vb.Net应用程序中找到了我想要做的类似设计,并且效果很好。我在这里遗漏了什么导致该隐式引用转换错误?

c# generics inheritance
2个回答
0
投票

这里有个建议。添加一个IBaseDLL接口。

  public interface IBaseBLL
  {
    //commom methods
  }

然后将其添加到您的BaseBLL类的列表接口中。

  public class BaseBLL<E, D> : BLLPai<D>, IBaseBLL
          where E : class, IBaseEntity
          where D : BaseData<E>
  {
    //commom methods
  }

现在您可以将基本控制器更改为以下内容:

[ApiController]
public abstract class GerenciadorLogadaCadastroController<Entidade, BLL> : ControllerBase
        where Entidade : IBaseEntity
        where BLL : IBaseBLL
{
}

-以撒


0
投票

我对您的代码做了一些简化,以简化为一个示例,该示例显示出了问题所在。有几个步骤。

这是我最初的简化:

public interface IBaseEntity { }
public class MyTable : IBaseEntity { }
public class BaseData<E> where E : IBaseEntity { }
public class MyTableData : BaseData<MyTable> { }
public class BaseBLL<E, D> where E : IBaseEntity where D : BaseData<E> { }
public class MyTableBLL : BaseBLL<MyTable, MyTableData> { }
public abstract class Controller<E, B> where E : IBaseEntity where B : BaseBLL<E, BaseData<E>> { }
public class MyTableController : Controller<MyTable, MyTableBLL> { }

现在,到此为止,不需要复制代码的整个IBaseEntity部分,因此我将其删除:

public class BaseData { }
public class MyTableData : BaseData { }
public class BaseBLL<D> where D : BaseData { }
public class MyTableBLL : BaseBLL<MyTableData> { }
public abstract class Controller<B> where B : BaseBLL<BaseData> { }
public class MyTableController : Controller<MyTableBLL> { }

现在我对类型进行了一些巧妙的重命名:

public class Fruit { }
public class Apple : Fruit { }
public class BowlOf<D> where D : Fruit { }
public class BowlOfApples : BowlOf<Apple> { }
public abstract class Controller<B> where B : BowlOf<Fruit> { }
public class BowlOfApplesController : Controller<BowlOfApples> { }

然后显示的是,当您定义Controller<BowlOfApples>时,您说的是BowlOfApples必须继承自BowlOf<Fruit>。但是BowlOfApples继承自BowlOf<Apple>,而不是BowlOf<Fruit>

此约束应该有意义。假设BowlOf<T> : List<T>并且有Banana : Fruit,然后想象这段代码是合法的:

BowlOf<Apple> apples = new BowlOf<Apple>();
BowlOf<Fruit> fruit = apples; // BOOM!!! imagine if this could be done!
Banana banana = new Banana();
fruit.Add(banana);

我们有可以将Banana添加到BowlOf<Apple>的代码!那不可能非法的事情是将BowlOf<Apple>强制转换为BowlOf<Fruit>

简单地放置BowlOf<Apple> 不继承自 BowlOf<Fruit>。尽管Apple继承自Fruit

当您尝试将BaseBLL<MyTable, MyTableData>设置为BaseBLL<MyTable, BaseData<MyTable>>时,您的代码正在犯同样的错误。

您确实在问题中确定此更改将起作用:

public abstract class Controller<F, B> where F : Apple where B : BowlOf<F> { }
public class BowlOfApplesController : Controller<Apple, BowlOfApples> { }

所以当您说“但是我不想键入Data类,因为它已经包含在BLL类中。”好吧,你无法避免。

© www.soinside.com 2019 - 2024. All rights reserved.