C# 公开接口而不是具体类

C# 公开接口而不是具体类,c#,C#,我最近读了一些关于在公开集合而不是具体实现(IEnumerable而不是List)时使用接口的内容。我现在正在我的代码中尝试这样做。然而,当我公开一个返回IEnumerable的属性时,我遇到了一些困难,不能将null作为返回值。例如: public class HumanResource { public IEnumerable<EmployeeModel> Employees { get { // retur

我最近读了一些关于在公开集合而不是具体实现(IEnumerable而不是List)时使用接口的内容。我现在正在我的代码中尝试这样做。然而,当我公开一个返回IEnumerable的属性时,我遇到了一些困难,不能将null作为返回值。例如:

public class HumanResource
{
    public IEnumerable<EmployeeModel> Employees
    {
        get
        {
            // return what?
        }
    }
}
公共类人力资源
{
公共雇员人数
{
得到
{
//还什么?
}
}
}
我应该在getter中返回什么?我不想对此使用自动属性,因为我想避免空值。我想要的是返回一个没有项目的新集合。当然,我可以返回实现IEnumerable的任何类型,但是类的外部用户如何知道呢?还是我理解这个公开接口而不是具体实现是错误的

编辑:删除了setter

当然,我可以返回实现IEnumerable的任何类型,但是类的外部用户如何知道呢

他们不必知道,这正是重点

您的属性承诺返回一个
IEnumerable
,这就是实际情况。代码返回哪个类实现这个接口并不重要

我想要的是返回一个没有项目的新集合

所以,
Enumerable.Empty()
newlist()
就可以了


在设计API时,您需要考虑消费者将如何处理您返回的数据类型,并据此做出决定


通常,集合的
IEnumerable
适合每个人。当他们想将它放在列表中时,他们可以执行
新建列表(yourEnumerable)
,或
yourEnumerable.ToArray()
将其用作数组。

您仍然需要为类中的属性提供内部支持集合。可以在构造函数或字段声明中初始化集合:

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
  }
}
使用内部
IEnumerable

//不太可能有用
私有只读IEnumerable_employees=new List();
TL;DR

  • 使用适合类内部使用的集合类型(OO组合)
  • 但是在外部接口(例如公共getter/property)上,将内部实现隐藏到最低限度(OO封装)
  • 在构造函数(或内联)中初始化内部集合将防止暴露空集合
我想要的是返回一个没有项目的新集合

属性使您可以非常轻松地执行此操作:

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 {};
    }
}
公共类人力资源
{
//这是当其不为null时返回的真实员工
私有IEnumerable employees;//可以为空
//这是employees为null时返回的空IEnumerable
私有静态只读IEnumerable EmptyEmployees=
新员工模型[0];
公共雇员人数
{
得到
{
返回员工??空员工;
}
集合{};
}
}
employees
变量设置为
null
时,代码返回空数组。您可以将
employees
设置为实现
IEnumerable
的任何类型的集合,甚至可以设置为数组(如果愿意)。这是可能的,因为您通过接口返回


当然,另一方面,客户端将无法直接访问未通过接口公开的属性方法。例如,如果
员工
实际上是一个
列表
,则调用者必须使用LINQ的
Count()
,而不是直接获取
.Count
。当然,您可以公开一个不同的接口,比如说,
IList
,让您的客户机使用其他方法。

您需要一个setter吗?现在还不清楚你想在这里实现什么。。。你想从哪里得到这些信息?嗨,乔恩。假设信息来自数据库。我们将数据放在一个实现IEnumerable(比如List)的集合中。对于该类的外部用户,他知道该属性返回IEnumerable,但他可以将其分配给数组或实现IEnumerable的任何其他集合,但这将导致错误。不,他们不能将其分配给数组或其他类型的变量-不能不强制转换。他们可以从序列中创建一个新数组,但那是另一回事。公开接口的意义在于,调用方不应该关心实现类型。我不确定我是否得到了它,但从您键入的内容来看,我的理解是,返回一个实现IEnumerable的列表或任何其他集合是可以的,如果需要的话,让调用方担心创建自己的集合?如果是这样的话,如果是你,你会在这里返回什么?我不知道我会返回什么-这取决于你如何从数据库中获取它,是否缓存它,是否相信调用方不会返回到
列表
并改变集合等。嗨,我知道这一点,但我的问题是,将使用该类的用户如何知道它返回的类型。例如,在您的示例中,您返回了一个列表。但是当外部用户使用这个类时,他只知道属性返回IEnumerable。如果他将其分配给类型数组(该数组也实现IEnumerable),则会出现错误。我希望我问的问题是正确的。通过提供
IEnumerable
接口,我们可以防止调用方a)重新分配和b)从内部
\u员工
集合中添加/删除元素。调用方可以将项目拉入自己的数组(例如,
myHumanResource.Employees.ToArray()
)您好,谢谢您的评论。根据我在您键入的内容中收集的信息,可以返回任何具体的类实现
// Unlikely to be useful
private readonly IEnumerable<EmployeeModel> _employees = new List<EmployeeModel>();
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 {};
    }
}