【问题标题】:c# generic type on where constraintc#泛型类型关于where约束
【发布时间】:2017-04-08 14:06:27
【问题描述】:

我有下面的简单对象模型,其中 Manager 类由子对象列表组成,子对象必须引用它的父对象:

public class ManagerBase<T1> where T1 : ChildBase<???>
{
    public ManagerBase()
    {
        ChildObjects = new List<T1>();
    }

    public List<T1> ChildObjects { get; set; }
}

public class ChildBase<T1> where T1 : ManagerBase<???>
{
    public ChildBase(T1 parentMgr)
    {
        ParentMgr = parentMgr;
        ParentMgr.ChildObjects.Add(this);
    }

    public T1 ParentMgr { get; set; }
}

以上是基础类。现在,下面是继承的示例 Manager 和 Child 类。我不知道如何使下面的类进行编译,因为上面的 BASE 类还无效。你能帮忙吗?谢谢。

public class CatalogManager : ManagerBase<Catalog>
{
}

public class Catalog : ChildBase<CatalogManager>
{
}

为了提供更清晰的想法:我有 BASE Manager 类,BASE Child Object 类。有不同类型的继承管理器(CatalogManager、DocumentManager 等)和不同类型的子对象(Catalog、文档等)。现在,每个 Manager 必须由 List 而不是 List 组成。 F.e:带有列表的 CatalogManager,带有列表的 DocumentManager。同时,每个子对象都必须引用它的Manager。换句话说,我需要强类型而不是使用基类。希望清楚。感谢您的宝贵时间。

【问题讨论】:

    标签: c# generics inheritance generic-programming


    【解决方案1】:

    您可以通过为通用基类创建非通用基类来实现这一点。更新答案以避免类型转换;为此,ChildObjects 属性必须是 IEnumerable&lt;T&gt;,因为它的类型参数是协变的,而类 IList&lt;T&gt;ICollection&lt;T&gt; 是逆变的。

    public abstract class ManagerBase
    {
        protected ManagerBase()
        {
            innerChildObjectList = new List<ChildBase>();
        }
        private IList innerChildObjectList;
        public IEnumerable<ChildBase> ChildObjects
        {
            get
            {
                foreach (ChildBase child in innerChildObjectList.OfType<ChildBase>())
                    yield return child;
            }
        }
        public void AddChild<T>(T child) where T : ChildBase
        {
            innerChildObjectList.Add(child);
        }
        public void RemoveChild<T>(T child) where T : ChildBase
        {
            innerChildObjectList.Remove(child);
        }
        public bool ContainsChild<T>(T child) where T : ChildBase
        {
            return innerChildObjectList.Contains(child);
        }
        //Add 'Insert', 'RemoveAt' methods if needed.
    }
    public abstract class Manager<T>
        : ManagerBase
        where T : ChildBase
    {
        public new IEnumerable<T> ChildObjects
        {
            get { return base.ChildObjects.OfType<T>(); }
        }
    }
    public abstract class ChildBase
    {
        protected ChildBase(ManagerBase mgr)
        {
            ParentMgr = mgr;
        }
        private ManagerBase parentMgr;
        public ManagerBase ParentMgr
        {
            get { return parentMgr; }
            set
            {
                if (parentMgr != null && parentMgr.ContainsChild(this))
                    parentMgr.RemoveChild(this);
                parentMgr = value;
                parentMgr.AddChild(this);
            }
        }
    }
    public abstract class Child<T>
        : ChildBase
        where T : ManagerBase
    {
        protected Child(T mgr) : base (mgr)
        {
        }
        public new T ParentMgr
        {
            get { return base.ParentMgr as T; }
            set { base.ParentMgr = value; }
        }
    }
    

    现在一切都会好的:

    public class CatalogManager : Manager<Catalog>
    {
    }
    
    public class Catalog : Child<CatalogManager>
    {
        public Catalog(CatalogManager parentMgr) : base(parentMgr)
        {
    
        }
    }
    

    【讨论】:

    • 这是一个很好的做法,因为它涉及每次访问 ParentManager 或 Childs 时的强制转换?谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多