Return Object type as Interface C#

Viewed 103

I am trying to return Interface as my return type from a method which provides data from two different data source with couple of different column. My implementation goes as below:

Interface:

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

BasicDTO abstract class:

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; }
}

Derived Class CBasicDTO:

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

Derived Class LBasicDTO

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

Implantation 1 Method:

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;
        }
    }

I am not getting any error at Compile time, but at run-time I am getting bellow error at return (IList<IBasicDTO>)data;

Error:

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

If I go with below implementation:

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;
        }
    }

I am getting below error at run-time:

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

Merging this data points in single data source is not an option for us as these data source is very large and CBasicDTO is already in production.

Please help me to solve this problem.

1 Answers

You need to cast each of the elements in the collection to the instance type, linq has a .Cast<T>() extension that will help:

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();
    }
}
  • You cannot simply cast the result, because in many implementations the result will be IEnumerable<T> but not an IList<T>
  • It IS necessary to call data.ToList() to execute the DB query first.
  • It is NOT necessary to cast to IList<T> as a List<T> already matches that signature
  • We have to call .ToList() at the end to match the IList<T> return signature.
Related