【发布时间】:2016-06-06 00:26:56
【问题描述】:
我在 List 和 IEnumerable 之间的协变/逆变方面遇到了一些问题,很可能我没有完全理解这个概念。我的类必须是具有具体属性的具体,以便它们可以使用 ServiceStack 通过网络进行序列化(SS 无法正确反序列化接口,它们最终为空属性,我之前从 mythz 中找到了一个线程,说明他们不想要支持 IoC,并且您的 DTO 应该始终只是具体的。如果这种态度发生了变化,或者有人知道快速的解决方法,那就太好了。)
关于我们的架构:
- 我们有 EF Code First,它将在 Schema 项目 (DLL) 中拥有像 User 这样的实体
- 我们在接口项目 (DLL) 中有一个接口
IUserModel - 我们有一个
UserModel,它与 User 具有相似的属性,但在模型项目 (DLL) 中添加了更多属性,以便于存储为域和 DTO 模型。 - 我们在像
CreateUser这样的服务项目中有一个实际的ServiceStack DTO,它继承了UserModel(以减少服务项目中的代码量,因为它实际上与UserModel具有相同的属性,但是使用 ServiceStack 路由,我们可以对CreateUser和UpdateUser使用相同的UserModel等)
下面是我们基本上随处可见的领域模型的 sn-p。有超过 200 个对象与数据库中的表相关,但不是实际的 EF 代码优先模型,因此我们可以在它们之间保留一个抽象层)
// Interface is in a lower level project that only has
// interfaces in it, no concretes
public interface IHaveNotesBaseModel
{
List<INoteModel> Notes { get; set; }
}
// Concrete implements the interface explicitly so it can have
// the Concrete for ServiceStack serialization/deserialization
public class UserModel : IHaveNotesBaseModel
{
public List<NoteModel> Notes { get; set; }
List<INoteModel> IHaveNotesBaseModel.Notes
{
get { return Notes?.ToList<INoteModel>(); }
set { Notes = value?.Cast<NoteModel>().ToList(); }
}
}
直到今天,我们都认为这是可行的,因为在我们的工作流层中,我们正在尝试对接口进行编程,它正在将内容添加到最终映射下来的 User.Notes 列表中,但我们今天发现了一个场景,其中IUserModel 被传递到函数中,NoteModel 被添加到 Notes,但如果你以后在哪里调用具体的 Notes,它没有那个对象。
我们一直在研究解决此问题的方法,发现.ToList<INoteModel>() 正在复制原件,这似乎是它无法正常工作的原因。我们需要一种无需复制列表即可从具体接口转换为继承接口的方法。
所以我们知道我们不能因为 ServiceStack 做的事情是:
- 更改为
IEnumerable<T>:ServiceStack 不会反序列化 IEnumerable,因为它是一个接口 - 进行演员表
(List<INoteModel>)Notes:演员表异常 - 在
.Cast<T>、(List<INoteModel>)Notes.Cast<INoteModel>()之后执行转换:转换异常
【问题讨论】:
标签: c# list servicestack ienumerable covariance