【问题标题】:Casting List<Concrete> to List<InheritedInterface> without .ToList() copy action在没有 .ToList() 复制操作的情况下将 List<Concrete> 转换为 List<Inherited Interface>
【发布时间】: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 路由,我们可以对 CreateUserUpdateUser 使用相同的 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&lt;INoteModel&gt;() 正在复制原件,这似乎是它无法正常工作的原因。我们需要一种无需复制列表即可从具体接口转换为继承接口的方法。

所以我们知道我们不能因为 ServiceStack 做的事情是:

  1. 更改为 IEnumerable&lt;T&gt;:ServiceStack 不会反序列化 IEnumerable,因为它是一个接口
  2. 进行演员表(List&lt;INoteModel&gt;)Notes:演员表异常
  3. .Cast&lt;T&gt;(List&lt;INoteModel&gt;)Notes.Cast&lt;INoteModel&gt;() 之后执行转换:转换异常

【问题讨论】:

    标签: c# list servicestack ienumerable covariance


    【解决方案1】:

    试试这个

     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(); }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-14
      • 2013-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-05
      相关资源
      最近更新 更多