Reputation: 1241
Edited after initial suggestions about using IEnumerable instead of List.
I am trying to do this:
public interface IKPIDetails // Previously: interface IKPIDetails
{
string name {get; set;}
//...
}
public abstract class BaseReport
{
public List<IKPIDetails> m_KPIDetails; // Previously: list<IKPIDetails> m_KPIDetails;
public BaseReport()
{
m_KPIDetails = MakeReportDataStructure();
//...
}
public abstract List<IKPIDetails> MakeReportDataStructure(); // Previously: public abstract IKPIDetails MakeReportDataStructure();
//...
}
public class AirTemp_KPIDetails : NetVisSolution.Reports.IKPIDetails // Previously: protected class AirTemp_KPIDetails : IKPIDetails
{
#region IKPIDetails implementation
private string _Name;
public string Name
{
get { return _Name; }
set { _Name = value; }
}
#endregion
...
}
public class SSAirTempSummaryReport : BaseReport
{
public SSAirTempSummaryReport() : base ()
{
// Do any extra initialisation here
m_reportName = "Air Temperature Summary Report";
}
//It now complains on the declaration below at the word
// MakeReportDataStructure()
public override IEnumerable<IKPIDetails> MakeReportDataStructure() // Previously: public override List<IKPIDetails> MakeReportDataStructure()
{
List<AirTemp_KPIDetails> d = new List<AirTemp_KPIDetails>();
return d; // <-- this is where it used to break
}
//...
}
So I have a report data object interface and potentially multiple report data classes implementing this interface and adding their specific extra bits. And I have an abstract report class implementing generic report functionality and multiple derived classes that each use their own report data class.
Unfortunately, when I try to create a list of my report detail structures in the derived class and pass it back to the base class as a list of the interface, it complains:
Cannot implicitly convert type
'System.Collections.Generic.List<NetVisSolution.Reports.AirTemp_KPIDetails>' to
'System.Collections.Generic.List<NetVisSolution.Reports.IKPIDetails>'
It won't let me do it implicitely or explicitly. Is there any way that I can do this?
Thanks in advance,
--- Alistair.
Upvotes: 1
Views: 784
Reputation: 3358
public override List<IKPIDetails> MakeReportDataStructure()
{
List<AirTemp_KPIDetails> d = new List<AirTemp_KPIDetails>();
return d; // <-- this is where is breaks
}
Should be:
public override List<IKPIDetails> MakeReportDataStructure()
{
List<IKPIDetails> d = new List<AirTemp_KPIDetails>();
return d;
}
Your assignment does not work, because in List<T>
, type argument T
is not covariant, that is, assignment is not allowed when T
is more specific. Should you use IEnumerable
, your code would work fine:
public override IEnumerable<IKPIDetails> MakeReportDataStructure()
{
List<AirTemp_KPIDetails> d = new List<AirTemp_KPIDetails>();
return d; // <-- works, because T in IEnumerable is covariant
}
You may ask, why IEnumerable
is covariant? Well, IEnumerable
only allows you to read data (hence covariance is marked with <out T>
), and you cannot write any object into it. List allows you to write objects into collection, and you would run into danger that you would later write less specific type to that collection, which could cause error, as less specific type does not provide same functionality as more derived one:
public override IEnumerable<BaseClass> MakeList()
{
List<DerivedClass> d = new List<DerivedClass>();
// ...
return d; // assume it would work
}
var l = MakeList();
l.Add(BaseClass); // now we added object of BaseClass to the list that expects object of DerivedClass, any operation on the original list (the one with List<DerivedClass> type could break
Upvotes: 4
Reputation: 1774
Try to use the below code.
public override List<IKPIDetails> MakeReportDataStructure()
{
return new List<AirTemp_KPIDetails>() as List<IKPIDetails>;
}
Upvotes: 0
Reputation: 3056
you shouldn't cast a List of one type to another because, then either the insert operation would fail, or the getting.
example: type A implements(extends) type B
List<A> listA;
List<B> listB;
((List<B>) listA).add(new B());
if this would legal, then you break the listA invariant by putting something more general than A.
A a = ((List<A>) listB).get(); //like get first, or something similar
this would break the fact that only A objects, could be assigned to the A reference.
Upvotes: 1
Reputation: 51634
You must create the list as a list of the interface, not the derived type:
List<IKPIDetails> d = new List<IKPIDetails>();
Upvotes: 0
Reputation: 12513
These two lists are different, even though AirTemp_KPIDetails
my be a IKPIDetails
(i.e. have an is-a-relation). You must copy the elements from one list to the other:
kpiDetailsList = new List<IKPIDetails>(airTempKPIList);
In general this belong to the subject of Co- and Contra-Variance. You may want to read the Wiki Article on Covariance and contravariance (computer science).
Upvotes: 1