Nig*_* DH 5 c# generics interface
我正在尝试创建一个通用接口,它允许我使用与数据库交互的方法.我希望我的业务应用程序能够实例化任何连接方法,并确保接口是相同的.
这是我现在正在尝试的简化版本.
数据库接口,其中IElement是另一个定义表的接口.
public interface IDatabase
{
void setItem( IElement task ); //this works fine
List<T> listTasks<T>() where T : IElement; // this doesn't
}
Run Code Online (Sandbox Code Playgroud)
IElement界面:
public interface IElement
{
int id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
IElement的实施:
public class TaskElement: IElement
{
public int id { get; set; }
public string name {get; set; }
}
Run Code Online (Sandbox Code Playgroud)
IDatabase的实现:
public class SQLiteDb: IDatabase
{
public SqLiteDb( SQLiteConnection conn )
{
database = conn;
}
public void setItem( IElement task )
{
// works fine when passed a new TaskElement() which is an implementation of IElement.
database.Insert( task );
}
//it all goes off the rails here
public List<T> listItems<T>() where T : IElement
{
var returnList = new List<IElement>
foreach (var s in database.Table<TaskElement>())
{ returnList.Add(s); }
return returnList;
}
Run Code Online (Sandbox Code Playgroud)
我已经尝试了很多变化,但每个都给了我一个新的问题.例如,这里有两个错误.
1)
'SQLiteDb.listTasks<T>()'无法从用法中推断出方法的类型参数.尝试显式指定类型参数.
2)
无法隐式转换
'System.Collections.Generic.List<TaskElement>'为'System.Collections.Generic.List<T>'
我已经尝试将方法更改为使用显式类型,但在那里遇到了问题.如果我使用IElement(我的所有元素的通用接口)我不能返回TaskElement对象列表(我的实现IElement),因为它与返回类型(List<IElement>)不匹配,如果我将返回类型更改为List<TaskElement>我不再实现界面.
值得注意的是,如果我停止使用界面和泛型,我可以轻松地将其工作,但这似乎是使用界面的理想情况.也许当其他应用程序(如直接继承)可能更好时,我正努力将很多东西塞进接口中?
题
如何实现具有泛型返回值的接口,同时限制只能返回到另一个接口的实现的类型.
让我们仔细看看您的实现listItems:
public List<T> listItems<T>() where T : IElement
{
var returnList = new List<IElement>
foreach (var s in database.Table<TaskElement>())
{ returnList.Add(s); }
return returnList;
}
Run Code Online (Sandbox Code Playgroud)
您在这里所做的是编写一个方法,在该方法中,调用者可以询问他们想要在列表中出现的任何类型,只要该类型实现了IElement. 但是您的方法中的代码并没有为他们提供所需类型的列表,而是为他们提供了IElement. 所以这是违反合同的。
但你问题的真正根源是database.Table<TaskElement>()。那只能给你 的实例TaskElement。你需要做到这一点T,但要做到这一点,你需要一个额外的通用约束:
public List<T> listItems<T>() where T : IElement, new
{
var returnList = new List<T>
foreach (var s in database.Table<T>())
{
returnList.Add(s);
}
return returnList;
}
Run Code Online (Sandbox Code Playgroud)
这是因为database.Table<T>有一个new约束,这意味着只能给定具有零参数构造函数的类型(因为该方法将创建给定类的实例)。