接口过载
本文关键字:接口 | 更新日期: 2023-09-27 18:12:16
所以我认为我可能在我的实现中过于复杂的事情,但这就是我所做的:
- 我希望我的数据库由IRepository 表示
- SQLRepository是IRepository的一个具体实现。
- 我希望数据库中的所有表都用table表示。
- 我有一个名为Items的表,它由ItemsTable表示。
- Items Table中的每条记录用IItem表示。
- Item是IItem的具体实现。
现在我的问题是,在我的程序中,当我想使用List items = repository.Items.List();它不会编译,因为在ItemsTable中,ITable的实现返回IList而不是List。我可以返回IList,但我确实想使用一个具体的项目列表。
我能做得更好吗?
public interface ITable
{
IList<IItem> List();
bool Add(IItem item);
bool Delete(long itemId);
bool Find(long itemId);
}
public class ItemsTable : ITable
{
public IList<IItem> List()
{
IList<IItem> items = GetItems(); // GetItems return List<Item>, Item implements IItem.
return items;
}
.....
...
..
}
public class SQLRepository : IRepository
{
ITable items = new ItemsTable();
public ITable Items
{
get { return items; }
}
}
static void Main(string[] args)
{
var repository = new SQLRepository();
List<Item> items = repository.Items.List();
}
我有几句话要对你说。
首先,仅仅因为你定义了映射到你的具体类的接口,你不需要在任何地方都使用接口。使用接口列表的目的是限制存储库和对象的用户可以使用的表面区域。因此,可以随意返回List<T>
,而不是IList<T>
。
其次,但是,返回任何实现IList<T>
的东西都意味着您希望在从存储库获得列表后修改列表的内容。这样做可能是不好的,而且有很多不好的原因。
如果你的存储库保留了它返回的列表的引用,那么随后的调用者可以得到你修改过的列表——所以你真的不能保留引用。因此,您需要为每个调用构建列表。
如果您为每个调用构建列表,那么您在返回结果之前有效地调用.ToList
操作符。
另一种方法是允许调用者决定何时调用.ToList
,然后您可以返回IEnumerable<T>
。
现在这在很多方面都更好了。
它让调用代码知道列表没有被另一个调用者修改。它还允许列表在每次新迭代时重新查询自己。
所以,我的建议是-不要返回IList<T>
或List<T>
-返回IEnumerable<T>
而不是让调用者调用.ToList()
。
最好将你的界面更改为:
public interface ITable<TItem>
where TItem : IItem
{
IList<TItem> List();
bool Add(TItem item);
bool Delete(long itemId);
bool Find(long itemId);
}
现在我的问题是,在我的程序中,当我想使用List items = repository.Items.List();它不会编译,因为在ItemsTable中,ITable的实现返回IList而不是List。我可以返回IList,但我确实想使用一个具体的项目列表。
。你不能两者兼得。如果您想使用List<T>
,则需要返回一个。你不能创建一个合约,说任何IList<T>
实现都是可以的,然后期望返回一个List<T>
。
这种违反通常会导致未来的维护混乱,因为IList<IItem> List();
承诺一件事,而你期望它交付其他东西。这就像你去加油站,点了无铅汽油,却期待加的是含铅汽油(它仍然是汽油,但有一点铅)。
. net中对于泛型集合没有差异。
显式地实现接口方法,并提供返回具体列表的重载:
public MyTable : ITable
{
IList<IItem>ITable List()
{
return List().OfType<IItem>().ToList();
}
public List<MyItem> List()
{
var l = new List<MyItem>();
...
return l;
}
}