我在List和IEnumerable之间的协方差/矛盾方面遇到了一些麻烦,很可能我没有完全理解这个概念。我的课程必须是具有Concrete属性的Concrete,以便它们可以使用ServiceStack在线路上进行序列化(SS不能正确地反序列化接口,它们最终会返回null属性,我之前从myzz中找到了一个线程,表明他们不希望这样做支持IoC,并且您的DTO始终应该是具体的。如果这种态度发生了变化,或者有人知道快速的解决方法,那就太好了。)
关于我们的架构的一些知识:
我们在架构项目(DLL)中拥有EF Code First,它将具有类似于User的实体
我们在接口项目(DLL)中有一个IUserModel
接口
我们有一个UserModel
,它具有与User相似的属性,但是在Models项目(DLL)中添加了更多域和DTO模型以便于存储。
我们在像CreateUser
这样的Service项目中有一个实际的ServiceStack DTO,它继承了UserModel
(以减少Service项目中的代码量,因为它实际上与UserModel
是相同的属性,但带有ServiceStack路由,我们可以对UserModel
和CreateUser
使用相同的UpdateUser
等)
以下是我们作为Domain模型基本上到处都有的代码片段。数据库中有超过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
,但是如果以后要在其中调用Concrete Notes
,则该对象不存在。我们一直在研究解决此问题的方法,发现
.ToList<INoteModel>()
正在复制原始副本,这似乎是无法正常工作的原因。我们需要一种无需复制列表即可从具体对象投射到继承的接口的方法。因此,我们知道由于ServiceStack而无法做的事情是:
更改为
IEnumerable<T>
:ServiceStack不会反序列化IEnumerable,因为它是一个接口执行强制转换
(List<INoteModel>)Notes
:强制转换异常在
.Cast<T>
,(List<INoteModel>)Notes.Cast<INoteModel>()
之后执行Cast:强制转换异常 最佳答案
尝试这个
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(); }
}
}
关于c# - 在没有.ToList()复制 Action 的情况下将List <Concrete>转换为List <Inherited Interface>,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35589884/