我最近在展示集合而不是具体实现(IEnumerable而不是List)时阅读了有关使用接口的内容。我现在在我的代码中尝试这样做。但是,当我公开一个返回IEnumerable的属性时,我很难不允许空值作为返回值。例如:
public class HumanResource
{
public IEnumerable<EmployeeModel> Employees
{
get
{
// return what?
}
}
}
我应该在吸气剂中返回什么?我不想为此使用自动属性,因为我想避免空值。我想要的是返回一个没有项目的新集合。当然我可以返回任何实现IEnumerable的类型,但该类的外部用户将如何知道?或者我是否理解这个暴露界面而不是具体的实现错误?
编辑:删除了二传手
答案 0 :(得分:5)
当然我可以返回任何实现IEnumerable的类型,但该类的外部用户将如何知道?
他们不必知道,这正是重点。
您的财产承诺会返回IEnumerable<EmplyeeModel>
,而这正是发生的事情。
我想要的是返回一个没有项目的新集合。
因此,Enumerable.Empty<EmplyeeModel>()
或new List<EmployeeModel>()
会很好。
在设计API时,您需要考虑消费者对您返回的数据类型的处理方式,并相应地做出决定。
通常,集合的IEnumerable<T>
适合所有人。当他们想要列表时,他们可以new List<T>(yourEnumerable)
或yourEnumerable.ToArray()
将其用作数组。
答案 1 :(得分:1)
我想要的是返回一个没有项目的新集合。
属性可让您轻松完成此操作:
public class HumanResource
{
// This is the real employees that gets returned when its not null
private IEnumerable<EmployeeModel> employees; // may be null
// This is the empty IEnumerable that gets returned when employees is null
private static readonly IEnumerable<EmployeeModel> EmptyEmployees =
new EmployeeModel[0];
public IEnumerable<EmployeeModel> Employees
{
get
{
return employees ?? EmptyEmployees;
}
set {};
}
}
当employees
变量设置为null
时,代码返回一个空数组。您可以将employees
设置为实现IEnumerable<EmployeeModel>
的任何类型的集合,如果您愿意,甚至可以设置为数组。这是可能的,因为您通过界面返回。
当然,另一方面,客户端无法直接访问未通过接口公开的属性方法。例如,如果employees
实际上是List
,则调用者必须使用LINQ Count()
而不是直接获取.Count
。当然,您可以公开一个不同的界面,比如IList<EmployeeModel>
,让您的客户使用其他方法。
答案 2 :(得分:0)
您仍需要为班级中的媒体资源提供内部支持集合。您可以在构造函数或字段声明中初始化集合:
public class HumanResource
{
private readonly IList<EmployeeModel> _employees = new List<EmployeeModel>();
public IEnumerable<EmployeeModel> Employees
{
get
{
return _employees;
}
// No Setter - callers may only enumerate the collection
}
}
顺便说一句,请注意,即使你确实使用了自动属性(例如List<EmployeeModel>
),它也会假定默认值为null,除非在别处初始化,所以在这方面没有任何变化。
编辑,回复:有什么好处?
HumanResource
的内部集合List<>
软化到IEnumerable<>
,这意味着调用者只能对内部集合执行只读操作,例如迭代它。此外,IEnumerable<>
可以在延迟迭代中使用,允许调用者在拥有所需数据后立即退出枚举。Array
,则LINQ扩展方法,例如.ToArray()
,.ToList()
,{{ 1}}可以使用。这样做会为调用者创建 new 集合,但会引用相同的.ToDictionary()
个对象。这样做的性能损失很小。最后要注意的是,将EmployeeModel
属性上的setter设为私有,或者将后备字段声明为IEnumerable
通常没有意义,因为这会阻止类本身使用impure操作集合的方法(即从中添加或删除对象),因为这样做需要强制转换,例如:
IEnumerable
我们在使用内部public class HumanResource
{
public IEnumerable<EmployeeModel> Employees
{
get;
private set;
}
public HumanResource()
{
// Although the property can be assigned in the CTor to prevent the null issue ...
Employees = new List<EmployeeModel>();
}
private void AddProductiveEmployee()
{
// ... We need to continually cast within the class, which is just silly.
(Employees as IList).Add(new EmployeeModel());
}
IEnumerable<>
TL; DR