我目前正在努力进行涉及通用列表的类设计:
代码说的超过千言万语:
class Document
{
public List<Result> Results { get; } = new List<Result>();
}
class Result
{
}
class SpecialDocument : Document
{
public new List<SpecialResult> Results { get; } = new List<SpecialResult>();
}
class SpecialResult : Result
{
}
我不喜欢当前的设计是SpecialDocument.Results
隐藏Document.Results
。如果在Document
上有SpecialDocument
视图,则根本没有结果,即使所有Result
元素都有SpecialResult
视图。
我想要完成的是:
SpecialDocument doc = new SpecialDocument();
doc.Results.Add(new SpecialResult());
Assert.AreEqual(1, (doc as Document).Results.Count); // Here my design obviously fails right now
...我想在不失去类型安全的情况下实现这一目标(因为这实际上是List<T>
不协变的原因。)
我忘了提及SpecialDocument
和Document
实际上需要具有相同的后继(或实现相同的接口),以便它们可以在一个集合中共存:
List<Document> documents = new List<Document>()
{
new Document(),
new SpecialDocument()
};
答案 0 :(得分:4)
你尝试过泛型吗?
abstract class Document<T> where T : Result
{
public List<T> Results { get; } = new List<T>();
}
abstract class Result
{
}
class SpecialDocument : Document<SpecialResult>
{
}
class SpecialResult : Result
{
}
SpecialDocument
会自动实例化List<SpecialResult>
。
答案 1 :(得分:1)
如果IDocument.Results
可以接受IEnumerable<Result>
类型而不是IList<Result>
,则可以使用。
由于协方差/反差方法规则,Result
属性必须以这种方式输入。
代码基于@Kyle B的优秀答案
void Main()
{
IDocument doc = new SpecialDocument();
//I added AddResult() to the interface to allow adding results, instead of calling Add() directly on the list.
doc.AddResult(new SpecialResult());
Assert.AreEqual(1, doc.Results.Count);
// prooving that the items can be added to a list, and that list can handle all the result types.
var docs = new List<IDocument>();
docs.Add(new Document());
docs.Add(new SpecialDocument());
var results = docs.SelectMany(d => d.Results)
// results now contains all results from all documents
}
abstract class Document<T> : IDocument where T : Result
{
public List<T> Results { get; } = new List<T>();
IEnumerable<Result> IDocument.Results => Results;
void IDocument.AddResult(Result result)
{
this.Results.Add((T)result);
}
}
abstract class Result
{
}
class Document : Document<Result>
{
}
class SpecialDocument : Document<SpecialResult>
{
}
class SpecialResult : Result
{
}
interface IDocument
{
IEnumerable<Result> Results { get; }
AddResult(Result result);
}