【问题标题】:Return Object type as Interface C#返回对象类型作为接口 C#
【发布时间】:2021-09-29 11:21:39
【问题描述】:

我试图从一个方法返回接口作为我的返回类型,该方法提供来自两个不同数据源和几个不同列的数据。我的实现如下:

界面:

public interface IBasicDTO
{
    int ID { get; set; }
    string EstablishmentCode { get; set; }
    DateTime? DetailsUpdatedDate { get; set; }
    DateTime? PaymentUpdatedDate { get; set; }
    UpdateStatus Status { get; set; }
}

BasicDTO 抽象类:

public abstract class BasicDTO : IBasicDTO, IModel
{
    public int ID { get; set; }
    public string EstablishmentCode { get; set; }
    public DateTime? DetailsUpdatedDate { get; set; }
    public DateTime? PaymentUpdatedDate { get; set; }
    public UpdateStatus Status { get; set; }
}

派生类 CBasicDTO:

public class CBasicDTO : BasicDTO
{
    public CBasicDTO() : base() { }
    public int? CID { get; set; }
    public string UniqueIdentificationNo { get; set; }
}

派生类 LBasicDTO

public class LBasicDTO : BasicDTO
{
    public LBasicDTO() : base() { }
    public int? LID { get; set; }
    public string LIdentificatonNo { get; set; }
}

植入1方法:

public IList<IBasicDTO> GetBasicData(int CID_LID, bool IsByLID)
    {
        SqlParameter parameter = new SqlParameter { ParameterName = "@p_CID", Value = CID_LID };
        if (IsByLID)
        {
            LLDbContext dataContext = new DBContextProvider().GetContext<LLDbContext>();
            var data = dataContext.Database.ExecuteProcedure<LBasicDTO>("Read_BasicDetails", parameter);
            return (IList<IBasicDTO>) data;

        }
        else
        {
            CIDbContext dataContext = new DBContextProvider().GetContext<CIDbContext>();
            var data = dataContext.Database.ExecuteProcedure<CBasicDTO>("Read_BasicDetails", parameter);
            return (IList<IBasicDTO>)data;
        }
    }

我在编译时没有收到任何错误,但在运行时我在 return (IList&lt;IBasicDTO&gt;)data; 收到以下错误

错误:

Unable to cast object of type 'System.Collections.Generic.List 1[NonTableTypes.CBasicDTO]' to type 'System.Collections.Generic.IList1[NonTableTypes.IBasicDTO]'.

如果我采用以下实现:

public IList<IBasicDTO> GetBasicData(int CID_LID, bool IsByLID)
    {
        SqlParameter parameter = new SqlParameter { ParameterName = "@p_CID", Value = CID_LID };
        if (IsByLID)
        {
            LLDbContext dataContext = new DBContextProvider().GetContext<LLDbContext>();
            var data = dataContext.Database.ExecuteProcedure<IBasicDTO>("Read_BasicDetails", parameter);
            return (IList<IBasicDTO>) data;

        }
        else
        {
            CIDbContext dataContext = new DBContextProvider().GetContext<CIDbContext>();
            var data = dataContext.Database.ExecuteProcedure<IBasicDTO>("Read_BasicDetails", parameter);
            return (IList<IBasicDTO>)data;
        }
    }

我在运行时遇到以下错误:

The result type 'NonTableTypes.IEPFBasicDTO' may not be abstract and must include a default constructor.

将这些数据点合并到单个数据源中不是我们的选择,因为这些数据源非常大,而且 CBasicDTO 已经投入生产。

请帮我解决这个问题。

【问题讨论】:

  • List&lt;LBasicDTO&gt;不是List&lt;IBasicDTO&gt;。如果允许该强制转换,您将能够在其中插入 CBasicDTO,尽管 single 列表对象仍声称是 LBasicDTO 对象的列表。
  • @Damien_The_Unbeliever 我明白了这一点,但是如何根据条件从方法中返回两个不同的派生类列表?

标签: c# entity-framework inheritance interface


【解决方案1】:

您需要将集合中的每个元素都转换为实例类型,linq 有一个 .Cast&lt;T&gt;() 扩展名,这会有所帮助:

public IList<IBasicDTO> GetBasicData(int CID_LID, bool IsByLID)
{
    SqlParameter parameter = new SqlParameter { ParameterName = "@p_CID", Value = CID_LID };
    if (IsByLID)
    {
        LLDbContext dataContext = new DBContextProvider().GetContext<LLDbContext>();
        var data = dataContext.Database.ExecuteProcedure<LBasicDTO>("Read_BasicDetails", parameter);
        return data.ToList().Cast<IBasicDTO>().ToList();

    }
    else
    {
        CIDbContext dataContext = new DBContextProvider().GetContext<CIDbContext>();
        var data = dataContext.Database.ExecuteProcedure<CBasicDTO>("Read_BasicDetails", parameter);
        return data.ToList().Cast<IBasicDTO>().ToList();
    }
}
  • 您不能简单地转换结果,因为在许多实现中,结果将是IEnumerable&lt;T&gt;,而不是IList&lt;T&gt;
  • IS必须先调用data.ToList() 来执行数据库查询。
  • 不需要强制转换为 IList&lt;T&gt;,因为 List&lt;T&gt; 已经匹配该签名
  • 我们必须在末尾调用.ToList() 以匹配IList&lt;T&gt; 返回签名。

【讨论】:

  • 它按预期工作。描述对于理解这个概念很有帮助。
  • 最终的ToList() 应该足以确保查询被执行和具体化。在大多数情况下,中间的ToList() 是不必要的,所以我不确定你为什么说它是必要的。
  • 在 .Net FX 中,您必须首先实现,Cast 必须在内存中完成,否则 EF 会在运行时抛出相同的错误 OP。我认为在 EF.Core 中这已得到修复,当它认识到它无法在数据库中完成时,它首先默默地实现。
猜你喜欢
  • 2017-05-15
  • 1970-01-01
  • 1970-01-01
  • 2012-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-15
相关资源
最近更新 更多