简体   繁体   中英

C# - What are the best practices when creating custom lists using arrays

I've got some school work to practice some concepts like generics, delegates, and interfaces. The whole project is to build a custom list class using an array of T . the class should also implement IEnumerable and have a struct which is an IEnumerator . I'm only focusing on the Add method here.

class MyList<T> : IEnumerable
{
    private static readonly T[] arrayStarter = new T[1];
    private int capacity = 1;
    private int currentItems = 1;

    public T[] TList { get; set; }

    public MyList()
    {
        TList = arrayStarter;
        TList[0] = default(T);
    }

    public  T[] Add(T[] tArray, T item)
    {
        T[] temp = new T[++capacity];
        for (int i = 0; i < tArray.Length; i++)
            temp[i] = tArray[i];
        temp[tArray.Length] = item;
        currentItems++;
        return temp;
    }
}

When I'm creating an instance of my list and I want to add an item using the method it looks like this:

MyList<int> m = new MyList<int>();
m.TList = m.Add(m.TList, 5);
m.TList = m.Add(m.TList, 7);
m.TList = m.Add(m.TList, 13);
m.TList = m.Add(m.TList, 15);

I'm pretty sure there's a better way to make a custom list I hope someone out there has a good insight on the matter.

This implementation demonstrates that you are missing the point of encapsulation in general, and of using private members in particular. Since you made TList array a member of your list class, you have an ability to hide it from your users completely. Your users should be able to write

m.Add(5);
m.Add(7);

instead of

m.TList = m.Add(m.TList, 5);
m.TList = m.Add(m.TList, 7);

and not worry about m.TList 's presence at all.

Fortunately, you can do it very easily: make TList a private field, rename it to something that starts in lower case letter to follow C#'s naming guidelines , remove it from the list of Add 's parameters, and change Add to not return anything. This would match IList<T> 's signature, which you should consider implementing.

Once you've made this work, consider "divorcing" capacity from currentItems , letting the first one grow faster, and the other one catching up to it as more items are added. This would reduce the number of re-allocations.

As a final point, consider switching to using Array.Resize<T> to avoid manual copying of data.

If you take a look at List<> 's Add() method implementation in ReferenceSource or with ILSpy, you'll see this:

private int _size;
private T[] _items;

public void Add(T item)
{
    if (this._size == this._items.Length)
    {
        this.EnsureCapacity(this._size + 1);
    }
    this._items[this._size++] = item;
    this._version++;
}

private void EnsureCapacity(int min)
{
    if (this._items.Length < min)
    {
        int num = (this._items.Length != 0) ? (this._items.Length * 2) : 4;
        if (num > 2146435071)
        {
            num = 2146435071;
        }
        if (num < min)
        {
            num = min;
        }
        this.Capacity = num;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM