[英]C# Return generic abstract class
我有以下類型層次結構:
public interface IDocument<TItem>
{
IEnumerable<TItem> Query(string query);
string FileName { get; }
}
public abstract class Document<TDocument, TItem> : IDocument<TItem>
{
public abstract IEnumerable<TItem> Query(string query);
public string FileName { get; private set; }
protected readonly TDocument _content;
}
public class DocumentX : Document<string, int>
{
...
}
public class DocumentY : Document<string, TypeOther>
{
...
}
等等...
我想創建一個工廠方法,如下所示:
private IEnumerable<IDocument<T>> Factory<T>()
where T : IDocument<T>
{
yield return new DocumentX();
yield return new DocumentY();
}
目標是擁有一個工廠方法,該方法將返回具有不同具體實現的集合,這些實現是從公共接口(IDocument)派生的
但是會引發編譯器錯誤:“無法將類型 'DocumentX' 隱式轉換為 'IDocument'。存在顯式轉換(您是否缺少強制轉換?)”
我錯過了什么?
這是對泛型的濫用。 如果你的方法是通用的,它不應該決定T
是什么。 調用者決定T
是什么。 現在,您的Factory
方法正在假設T
到底是什么。 這表明Factory
不應該是泛型的。
你想說什么,就像
嘿,
Factory
調用者,我將返回一堆IDocument<T>
,但您不知道每個的T
將是什么。
這就是將DocumentX
和DocumentY
放入IEnumerable
時會發生的情況。 想象一下,我正在使用Factory
返回的IEnumerable
。 我不知道我得到的每個元素是什么類型的文檔。 IE
foreach (IDocument<???> document in Factory()) {
??? queryResult = document.Query("some query");
}
我不知道我應該放什么???
.
嗯,實際上,我對Query
會返回什么有一點想法。 如果我寫:
foreach (IDocument<object> document in Factory()) {
object queryResult = document.Query("some query");
}
那會起作用,因為一切都可以轉換為object
。 所以我們只需要編寫一個符合IDocument<object>
的AnyDocument
類:
public class AnyDocument : IDocument<object> {
public string FileName { get; private set; }
private Func<string, IEnumerable<object>> query;
public IEnumerable<object> Query(string query)
{
return this.query(query);
}
private AnyDocument() { }
// this is used to convert an `IDocument<T>` to an AnyDocument
public static AnyDocument FromDocument<T>(IDocument<T> document) {
var doc = new AnyDocument();
doc.FileName = document.FileName;
doc.query = s => document.Query(s).Cast<object>();
return doc;
}
}
現在你可以像這樣聲明Factory
:
private IEnumerable<IDocument<object>> Factory()
{
yield return AnyDocument.FromDocument(new DocumentX());
yield return AnyDocument.FromDocument(new DocumentY());
}
這整個事情本來是簡單了很多,如果T
中IDocument<T>
被限制為引用類型,即沒有IDocument<int>
像DocumentX
。 因為那樣你就可以使用通用方差:
// just add the word "out"
public interface IDocument<out TItem>
實際上,我會說無論如何你都應該這樣做,因為如果T
是引用類型,你可以直接返回文檔對象,並且僅當T
是值類型時才使用AnyDocument
:
private IEnumerable<IDocument<object>> Factory()
{
yield return AnyDocument.FromDocument(new DocumentX());
yield return new DocumentY(); // let's say "OtherType" is a reference type
}
嘗試:
private IEnumerable<IDocument<T>> Factory<T>() where T : IDocument<T>, class
{
yield return new DocumentX() as T;
yield return new DocumentY() as T;
}
通過將DocumentX
、 DocumentY
為T
您可以確保所有這些都至少是IDcoument<T>
類型,如果不是實現IDocument<T>
的類T
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.