C#返回泛型抽象类

C#返回泛型抽象类,c#,generics,C#,Generics,我有以下类型层次结构: public interface IDocument<TItem> { IEnumerable<TItem> Query(string query); string FileName { get; } } public abstract class Document<TDocument, TItem> : IDocument<TItem> { public abstract IEnumerable

我有以下类型层次结构:

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>
{
    ...
}
公共接口IDocument
{
IEnumerable查询(字符串查询);
字符串文件名{get;}
}
公共抽象类文档:IDocument
{
公共抽象IEnumerable查询(字符串查询);
公共字符串文件名{get;private set;}
受保护的只读文件内容;
}
公共类DocumentX:Document
{
...
}
公共类文档:文档
{
...
}
等等

我想创建一个工厂方法,如下所示:

private IEnumerable<IDocument<T>> Factory<T>()
where T : IDocument<T>
{
    yield return new DocumentX();
    yield return new DocumentY();
}
private IEnumerable<IDocument<object>> Factory()
{
    yield return AnyDocument.FromDocument(new DocumentX());
    yield return AnyDocument.FromDocument(new DocumentY());
}
private IEnumerable工厂()
其中T:I文件
{
返回新文档x();
生成返回新文档();
}
我们的目标是拥有一个工厂方法,它将返回一个具有不同具体实现的集合,这些实现是从公共接口(IDocument)派生的

但编译器错误会引发: “无法将类型‘DocumentX’隐式转换为‘IDocument’。存在显式转换(是否缺少转换?)”


我错过了什么?

这是对泛型的滥用。如果你的方法是泛型的,它不应该决定什么是
T
。调用方决定什么是
T
。现在,您的
工厂
方法正在假设
T
到底是什么。这表明
工厂
不应该是通用的

你想说的是

嘿,
Factory
的调用方,我将返回一堆
I文档,但您不知道每个文档的
t
是什么

这就是将
DocumentX
DocumentY
放入
IEnumerable
中时发生的情况。假设我正在使用
工厂返回的
IEnumerable
。我不知道我得到的每个元素是什么类型的文档。i、 e

foreach (IDocument<???> document in Factory()) {
    ??? queryResult = document.Query("some query");
}
这是可行的,因为所有东西都可以转换为
对象
。所以我们只需要编写一个符合
i文档
AnyDocument
类:


如果
IDocument
中的
T
仅限于引用类型,即像
DocumentX
中一样,没有
IDocument
,那么整个过程可能会简单得多。因为这样您就可以使用通用方差:

// just add the word "out"
public interface IDocument<out TItem>

这是对仿制药的滥用。如果你的方法是泛型的,它不应该决定什么是
T
。调用方决定什么是
T
。现在,您的
工厂
方法正在假设
T
到底是什么。这表明
工厂
不应该是通用的

你想说的是

嘿,
Factory
的调用方,我将返回一堆
I文档,但您不知道每个文档的
t
是什么

这就是将
DocumentX
DocumentY
放入
IEnumerable
中时发生的情况。假设我正在使用
工厂返回的
IEnumerable
。我不知道我得到的每个元素是什么类型的文档。i、 e

foreach (IDocument<???> document in Factory()) {
    ??? queryResult = document.Query("some query");
}
这是可行的,因为所有东西都可以转换为
对象
。所以我们只需要编写一个符合
i文档
AnyDocument
类:


如果
IDocument
中的
T
仅限于引用类型,即像
DocumentX
中一样,没有
IDocument
,那么整个过程可能会简单得多。因为这样您就可以使用通用方差:

// just add the word "out"
public interface IDocument<out TItem>
尝试:

private IEnumerable工厂(),其中T:i文档,类
{
将新文档X()作为T返回;
返回新文档()作为T;
}
通过将
DocumentX
DocumentY
转换为
T
,您可以确保它们至少都是
IDcoument
类型,如果不是实现
IDcoument

的类
T
,请尝试:

private IEnumerable工厂(),其中T:i文档,类
{
将新文档X()作为T返回;
返回新文档()作为T;
}

通过将
DocumentX
DocumentY
转换为
T
,可以确保它们至少都是
IDcoument
类型,如果不是实现
IDocument

的类
T
,那么
DocumentX
对象就是一种
IDocument
,而不是一种
IDocument
。你想用你的工厂方法实现什么?很难知道你想达到什么目的。我已经扩展了我的帖子:所以我的工厂应该返回一个带有不同IDocument实现的集合。你打算给
factory
的通用参数是什么?难道
TDocument
永远不是一个
string
?一个
DocumentX
对象是一种
IDocument
,而不是一种
IDocument
。你想用你的工厂方法实现什么?很难知道你想达到什么目的。我已经扩展了我的帖子:所以我的工厂应该返回一个带有不同IDocument实现的集合。你打算给
factory
的通用参数是什么?难道
TDocument
永远不是一个
字符串
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;
}