我在List和IEnumerable之间的协方差/逆变方面遇到了一些麻烦,很可能我并不完全理解这个概念。我的类必须是具有Concrete属性的Concrete,以便它们可以使用ServiceStack进行序列化(SS可以正确地反向反序列化接口,它们最终为null属性,我之前发现了mythz的一个帖子,声明他们没有#&# 39;我想支持IoC并且你的DTO应该只是混凝土。如果这种态度发生了变化,或者有人知道快速的解决方法,那就太好了。)
关于我们的架构:
IUserModel
的接口UserModel
,它具有与User类似的属性,但在Models项目(DLL)中添加了更多以便于作为Domain和DTO模型的存储。CreateUser
这样的服务项目中有一个实际的ServiceStack DTO,它继承了UserModel
(以保持服务项目中的代码量减少,因为它实际上是与{的相同属性{1}},但使用ServiceStack路由,我们可以对UserModel
和UserModel
等使用相同的CreateUser
。)下面是我们的Domain模型中我们基本上拥有的内容片段。有超过200个对象与数据库中的表有关,但实际的EF代码不是第一个模型,所以我们可以在它们之间保留一个抽象层。
UpdateUser
直到今天,我们认为这是有效的,因为在我们的Workflows层,我们正在尝试编程接口,它正在向// 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
正在制作原件的副本,这似乎是它无法正常工作的原因。我们需要一种从具体到接口继承的方法,而不需要复制列表。
因此,我们所知道的因为ServiceStack而无法做到的事情是:
.ToList<INoteModel>()
:ServiceStack无法反序列化IEnumerable,因为它是一个界面IEnumerable<T>
:投射例外(List<INoteModel>)Notes
,.Cast<T>
:施放例外答案 0 :(得分:0)
试试这个
public class UserModel : IHaveNotesBaseModel
{
public List<NoteModel> Notes { get; set; }
List<INoteModel> IHaveNotesBaseModel.Notes
{
get { return Notes.Cast<INoteModel>().ToList(); }
set { Notes = value.Cast<NoteModel>().ToList(); }
}
}
完整示例:
class Program
{
static void Main(string[] args)
{
UserModel um = new UserModel();
um.Notes = new List<NoteModel>();
um.Notes.Add(new NoteModel { MyProperty = 1 });
um.Notes.Add(new NoteModel { MyProperty = 100 });
um.Notes.Add(new NoteModel { MyProperty = 10 });
um.Notes.Add(new NoteModel { MyProperty = 10000 });
List<INoteModel> Notes = um.Notes.Cast<INoteModel>().ToList();
((IHaveNotesBaseModel)um).Notes = Notes;
}
}
// 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.Cast<INoteModel>().ToList(); }
set { Notes = value.Cast<NoteModel>().ToList(); }
}
}