为了账号安全,请及时绑定邮箱和手机立即绑定

有效地从 List<T> 返回 IList<Interface>

有效地从 List<T> 返回 IList<Interface>

C#
四季花海 2021-07-01 14:03:59
我有以下代码:public interface ISomeObject{     IList<ISomeObject> Objects { get; }}public class SomeObject : ISomeObject{    public SomeObject()    {        Objects = new List<SomeObject>();    }    public List<SomeObject> Objects    {         get;         set;    }    IList<ISomeObject> ISomeObject.Objects    {            get         {            // What to do here?            // return Objects; // This doesn't work            return Objects.Cast<ISomeObject>().ToList(); // Works, but creates a copy each time.         }    }SomeObject有一个Objects返回类类型列表的公共属性。知道该类类型的客户可以使用它来做任何他们想做的事情。仅知道有关的客户只能ISomeObject使用该Objects属性来获取IList<ISomeObject>. 因为不允许转换List<SomeObject>为IList<ISomeObject>(由于苹果和香蕉问题),所以我需要一种转换方法。默认方式,使用 Cast.ToList() 工作,但有一个缺点,它每次评估属性时都会创建一个新列表,这可能很昂贵。更改ISomeObject.Objects为返回 anIEnumerable<ISomeObject>的另一个缺点是客户端不能再使用索引(这在我的用例中非常相关)。并且当在 IEnumerable 上使用时,重复使用 Linq 的 ElementAt() 调用是很昂贵的。有没有人知道如何避免这两个问题?(当然,SomeObject到处宣传不是一种选择)。
查看完整描述

3 回答

?
九州编程

TA贡献1785条经验 获得超4个赞

更改ISomeObject.Objects为返回 anIEnumerable<ISomeObject>的另一个缺点是客户端不能再使用索引(这在我的用例中非常相关)。

索引不仅受IList<T>接口支持,还受IReadOnlyList<T>接口支持。因为IReadOnlyList<T>不允许修改,所以它可以(并且是)协变,就像现在一样IEnumerable<T>

因此,只需将返回类型更改为IReadOnlyList<ISomeObject>并返回原始列表。

当然,没有什么可以阻止调用者将结果转换为List<SomeObject>,但是调用者应该拥有对该列表的完全访问权限,因此不存在安全风险。


查看完整回答
反对 回复 2021-07-03
?
ibeautiful

TA贡献1993条经验 获得超5个赞

您可能想尝试封装您List<SomeObject>的实现细节并返回IReadOnlyList<SomeObject>。然后SomeObjectISomeObject由于IReadOnlyList变化,在接口实现中也不需要强制转换 want - 你将能够返回你的Objectsas IReadOnlyList<ISomeObject>

然后只需添加一些操作来改变您的基础列表,如AddRemove容器类型(如果需要)。

我还要提到的接口不是那么好了限制-邪恶的消费者可以轻松地投你ISomeObjectSomeObject和他做想要的一切,或许,你应该重新考虑你的设计。你最好坚持不变性和封装性这样的东西来提供可用的api。显式使用可变构建器,然后在合理的情况下用于不可变类。


查看完整回答
反对 回复 2021-07-03
  • 3 回答
  • 0 关注
  • 193 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信