如何创建自己的通用列表类?

时间:2012-09-25 07:10:50

标签: c# generics linked-list

我有这个:

public class CChainElement
{
    public CChainElement m_Prev, m_Next;
}

public class CChainList : IEnumerable
{
    public CChainElement m_First;

    internal void Add(CChainElement Element)
    {
        if (m_First != null)
            m_First.m_Prev = Element;

        Element.m_Next = m_First;
        m_First = Element;
    }
}

public class CEntity : CChainElement
{
}

public class CItem : CEntity
{
}

public class CTest
{
    void Test()
    {
        CChainList AllItem = new CChainList();
        CItem Item = new CItem();

        AllItem.Add(Item);

        CItem FirstItem = AllItem.m_First as CItem;
        CItem SecondItem = FirstItem.m_Next as CItem;
    }
}

我想切换到这样的事情:

public class CChainElement<T> where T : CChainElement<T>
{
    public T m_Prev, m_Next;
}

public class CChainList<T> : IEnumerable where T : CChainElement<T>
{
    public T m_First;

    internal void Add(T Element)
    {
        if (m_First != null)
            m_First.m_Prev = Element;

        Element.m_Next = m_First;
        m_First = Element;
    }
}

public class CEntity : CChainElement<CEntity>
{
}

public class CItem : CEntity
{
}

public class CTest
{
    void Test()
    {
        CChainList<CItem> AllItem = new CChainList<CItem>();
        CItem Item = new CItem();

        AllItem.Add(Item);

        CItem FirstItem = AllItem.m_First;  // Yeepee, no more "as CItem" ..! ;-)
        CItem SecondItem = FirstItem.m_Next;
    }
}

我收到CItem can't be converted to CChainElement<CItem>

的错误

所以我的问题是:是否有约束public class CChainElement<T>因此它会优雅地采用CItem,即使它不直接从CChainElement继承?

我的目标显然是从CChainElement<T>继承的所有类都可以与我的通用列表类一起列出,同时避免显式转换。

提前感谢您的帮助!

编辑:在我的完整项目中,CEntity用于许多不同的事物作为抽象类(即:我可以通过类似于物品的方式操纵怪物),所以它不能被更改为通用CEntity<T>

2 个答案:

答案 0 :(得分:0)

CChainElement不应该是通用的。唯一应该变成通用的是CChainList

public class CChainElement
{
    public CChainElement m_Prev, m_Next;
}

public class CChainList<T> : IEnumerable
   where T : CChainElement
{
    public T m_First;

    internal void Add(T Element)
    {
        if (m_First != null)
            m_First.m_Prev = Element;

        Element.m_Next = m_First;
        m_First = Element;
    }
}

public class CEntity : CChainElement
{
}

public class CItem : CEntity
{
}

public class CTest
{
    void Test()
    {
        CChainList<CItem> AllItem = new CChainList<CItem>();
        CItem Item = new CItem();

        AllItem.Add(Item);

        CItem FirstItem = AllItem.m_First;
        CItem SecondItem = FirstItem.m_Next;
    }
}

答案 1 :(得分:0)

嗯,这是一个有趣的小问题。您需要进行以下更改:

public class CEntity<T> : CChainElement<T> where T : CChainElement<T> { ... }

public class CItem : CEntity<CItem> { ... }

然后这将以您想要的方式工作:

var allItems = new CChainList<CItem> { new CItem(), new CItem() };

// Both of these are now of type Item.
var firstItem = allItems.m_First;
var secondItem = firstItem.m_Next;

另一个选择是使ChainElement成为通用接口:

public interface IChainElement<T> where T : IChainElement<T>
{
    T Previous { get; set; }
    T Next { get; set; }
}

但是,您必须将属性显式添加到要放入列表中的每个类:

public class Entity { }

public class Item : Entity, IChainElement<Item>
{
    public Item Previous { get; set; }
    public Item Next { get; set; }
}

无论哪种方式,您最终都需要修改要在列表中使用的所有类。


另外,您可能希望使用更好的命名约定。使用C为所有类名称命名,使用InitialCapitals命名参数和本地人,以及以m_开头的公共字段使您的代码难以阅读!我会推荐这样的东西:

public class ChainElement<T> where T : ChainElement<T>
{
    public T Previous { get; set; }
    public T Next { get; set; }
}

public class ChainList<T> : IEnumerable where T : ChainElement<T>
{
    public T First { get; private set; }

    public void Add(T element)
    {
        if (First != null)
            First.Previous = element;

        element.Next = First;
        First = element;
    }

    public IEnumerator GetEnumerator() { throw new NotImplementedException(); }
}

public class Entity<T> : ChainElement<T> where T : ChainElement<T> { }

public class Item : Entity<Item> { }