【问题标题】:Need suggestion to Saving collections in Domain objects using list of generic collections需要建议使用通用集合列表在域对象中保存集合
【发布时间】:2011-04-03 16:54:47
【问题描述】:

我想让这个方法称为 RegisterCollection,目的是在 DomainObject 中注册子对象的集合。这个想法是我想在一个列表中注册集合,这样当我在我的 DomainObject 上调用 Save() 时,它会在每个注册的集合子域对象上调用 save。

我已编写此代码,但在构建时出现此错误:参数类型“OrderCollection”不可分配给参数类型集合

我在 .Net 3.5 中使用 C#。我在某处读到.NET 4.0 支持失败的转换类型。不确定这是否被正确理解,但无论如何,我希望有人对其他方法或解决方法提出一些建议。

这可能通过某种命令模式实现吗?

public interface IDomainObject
{
    void Save();
}

public class DomainObject : IDomainObject
{
    private readonly IList<Collection<IDomainObject>> m_Collections = new List<Collection<IDomainObject>>();

    protected void RegisterCollection(Collection<IDomainObject> collection)
    {
        m_Collections.Add(collection);
    }

    /// <summary>
    /// Saves this instance collections.
    /// </summary>
    public virtual void Save()
    {
        SaveCollections();
    }

    private void SaveCollections()
    {
        foreach (var itemCollection in m_Collections)
        {
            foreach (var item in itemCollection)
            {
                item.Save();
            }
        }
    }

}

public class OrderCollection : Collection<IOrder>
{

}

public interface IOrder : IDomainObject
{
}

public class Customer : DomainObject
{
    private readonly OrderCollection m_OrderCollection = new OrderCollection();

    public Customer()
    {
        // Throws: Argument type 'OrderCollection' is not assignable to parameter type Collection<IDomainObject>
        RegisterCollection(m_OrderCollection);
    }
}

【问题讨论】:

    标签: c# .net design-patterns generics collections


    【解决方案1】:

    您的问题是 Collection&lt;IOrder&gt;Collection&lt;IDomainObject&gt; 不兼容,这归结为 Covariance and Contravariance

    想象一下您的IOrder 集合,如果它被视为IDomainObject 的列表,那么这将允许您将任何IDomainObject 添加到列表中,这意味着我可以添加一个ISomethingElse,只要它源自IDomainObject,显然这将是一件坏事..

    【讨论】:

    • 我明白你的意思。但是,你能想出一个替代解决方案来解决我的问题吗,一个仍然允许我维护泛型集合列表的解决方案。
    【解决方案2】:

    您是否必须维护一个集合列表,或者您可以用一个简单的IDomainObject 列表替换它吗?

    如果是这样,您可以将RegisterCollection 设为通用:

    private readonly IList<IDomainObject> m_Collections = new List<IDomainObject>();
    
    protected void RegisterCollection<T>(Collection<T> collection) where T : IDomainObject {
      foreach (var obj in collection)
        m_Collections.Add(obj);
    }
    

    借助类型推断,您不必指定 T,并且可以使用派生自 IDomainObject 的任何类集合调用 RegisterCollection

    编辑:好的,我现在明白您为什么要保留该列表。我能想到的另一个解决方案是创建一个带有非泛型基类的自定义 Collection 类:

    public abstract class DomainObjectCollection {
        public abstract void Save();
    }
    
    public class DomainObjectCollection<T> : DomainObjectCollection where T : IDomainObject {
        private readonly Collection<T> collection;
    
        public DomainObjectCollection(Collection<T> collection) {
            this.collection = collection;
        }
    
        public static implicit operator DomainObjectCollection<T> (Collection<T> collection) {
            return new DomainObjectCollection<T>(collection);
        }
    
        public override void Save() {
            foreach (var obj in collection)
                obj.Save();
        }
    }
    
    public class DomainObject : IDomainObject {
        private readonly IList<DomainObjectCollection> m_Collections = new List<DomainObjectCollection>();
    
        protected void RegisterCollection<T>(Collection<T> collection) where T : IDomainObject {
            m_Collections.Add((DomainObjectCollection<T>)collection);
        }
    
        /// <summary>
        /// Saves this instance collections.
        /// </summary>
        public virtual void Save() {
            SaveCollections();
        }
    
        private void SaveCollections() {
            foreach (var itemCollection in m_Collections) {
                itemCollection.Save();
            }
        }
    
    }
    

    【讨论】:

    • 因为我希望稍后调用 Save(),所以我必须维护一个集合列表。使用您的建议,我最终会在调用 Registercollection 时获得集合中项目的快照,因此会错过在 Registercollection 和 Save 调用之间添加的对象。希望这有意义吗?无论如何感谢您的建议和努力。
    【解决方案3】:

    我想我已经找到了解决办法。它不漂亮,但它正在工作。让我知道你的想法。欢迎提出建议。

    请注意,我已将您的一些建议 Enzi 用于 RegisterCollection。

    这使我可以保持 SaveCollections 通用并在运行时添加更多集合。

    public class DomainObject : IDomainObject
    {
        private readonly IList<IList> m_Collections = new List<IList>();
    
        protected void RegisterCollection<T>(List<T> collection) where T : IDomainObject
        {
            m_Collections.Add(collection);
        }
    
        public int Id { get; set; }
    
        /// <summary>
        /// Saves this instance collections.
        /// </summary>
        public virtual void Save()
        {
            SaveCollections();
        }
    
        private void SaveCollections()
        {
            foreach (var itemCollection in m_Collections)
            {
                foreach (var item in itemCollection))
                {
                    ((IDomainObject)item).Save();
                }
            }
        }        
    }
    
    
    public interface IDomainObject
    {
        /// <summary>
        /// Gets or sets the id.
        /// </summary>
        /// <value>
        /// The id.
        /// </value>
        int Id { get; set; }
    
        /// <summary>
        /// Saves this instance.
        /// </summary>
        void Save();
    
        /// <summary>
        /// Deletes this instance.
        /// </summary>
        void Delete();
    }
    

    【讨论】:

    • 在上面编辑以反映更好的解决方案。希望对其他人有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-02
    相关资源
    最近更新 更多