If you came to C# from C++, you're going to notice rather fast that one data type is missing from the System.Collections namespace. Namely a vector class. In C++ there's the std::vector class which is used about any time that you need an array in C++ (unless of course you like recreating an array when you out grow it). In C#, there is no class like that. We have the List class, which is used with about the same frequency and has a similar function but you don't have that great of control over the capacity. I can set the capacity of it but I can't really control how much is added each time it needs to resize (not to mention I would prefer to have some sort of tie in with events, etc.). So I ended up creating my own Vector class.
/*
Copyright (c) 2009 <a href="http://www.gutgames.com">James Craig</a>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/
#region Usings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Utilities.Events.EventArgs;
using Utilities.Events;
#endregion
namespace Utilities.DataTypes
{
/// <summary>
/// Vector class
/// </summary>
/// <typeparam name="T">The type of item the vector should hold</typeparam>
public class Vector<T> : IList<T>
{
#region Constructor
/// <summary>
/// Constructor
/// </summary>
public Vector()
{
Items = new T[DefaultSize];
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="InitialSize">Initial size of the vector</param>
public Vector(int InitialSize)
{
if (InitialSize < 1) throw new ArgumentOutOfRangeException("InitialSize");
Items = new T[InitialSize];
DefaultSize = InitialSize;
}
#endregion
#region IList<T> Members
public int IndexOf(T item)
{
return Array.IndexOf<T>(this.Items, item, 0, this.NumberItems);
}
public void Insert(int index, T item)
{
if (index > this.NumberItems || index < 0) throw new ArgumentOutOfRangeException("index");
try
{
if (this.NumberItems == this.Items.Length)
{
Array.Resize<T>(ref this.Items, this.Items.Length * 2);
}
if (index < this.NumberItems)
{
Array.Copy(this.Items, index, this.Items, index + 1, this.NumberItems - index);
}
this.Items[index] = item;
++this.NumberItems;
EventHelper.Raise<ChangedEventArgs>(Changed, this, new ChangedEventArgs());
}
catch (Exception a) { throw a; }
}
public void RemoveAt(int index)
{
if (index > this.NumberItems || index < 0) throw new ArgumentOutOfRangeException("index");
try
{
if (index < this.NumberItems)
{
Array.Copy(this.Items, index + 1, this.Items, index, this.NumberItems - (index + 1));
}
this.Items[this.NumberItems - 1] = default(T);
--this.NumberItems;
EventHelper.Raise<ChangedEventArgs>(Changed, this, new ChangedEventArgs());
}
catch (Exception a) { throw a; }
}
public T this[int index]
{
get
{
if (index > this.NumberItems || index < 0) throw new ArgumentOutOfRangeException("index");
return this.Items[index];
}
set
{
if (index > this.NumberItems || index < 0) throw new ArgumentOutOfRangeException("index");
this.Items[index] = value;
EventHelper.Raise<ChangedEventArgs>(Changed, this, new ChangedEventArgs());
}
}
#endregion
#region ICollection<T> Members
public void Add(T item)
{
try
{
Insert(this.NumberItems, item);
}
catch (Exception a) { throw a; }
}
public void Clear()
{
try
{
Array.Clear(this.Items, 0, this.Items.Length);
this.NumberItems = 0;
EventHelper.Raise<ChangedEventArgs>(Changed, this, new ChangedEventArgs());
}
catch (Exception a) { throw a; }
}
public bool Contains(T item)
{
return (this.IndexOf(item) >= 0);
}
public void CopyTo(T[] array, int arrayIndex)
{
Array.Copy(this.Items, 0, array, arrayIndex, this.NumberItems);
}
public int Count
{
get { return this.NumberItems; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
int Index = this.IndexOf(item);
if (Index > 0)
{
this.RemoveAt(Index);
return true;
}
return false;
}
#endregion
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
for (int x = 0; x < this.NumberItems; ++x)
{
yield return this.Items[x];
}
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
for (int x = 0; x < this.NumberItems; ++x)
{
yield return this.Items[x];
}
}
#endregion
#region Protected Variables/Properties
protected int DefaultSize = 2;
protected T[] Items = null;
protected int NumberItems { get; set; }
#endregion
#region Events
public EventHandler<ChangedEventArgs> Changed;
#endregion
}
}
Most of the class above is pretty straight forward. We have an array of elements and each time we insert an item and need to increase the size of the array, we double its size. If you wanted you could switch it from multiplying by two to a fixed size (a simple change really). The only portion which may not jump out at you though is the fact that there is an EventHandler class in there. An EventHandler is basically a generic class that holds a method that handles an event. It's not mine, just a .Net class. But it's defined with a ChangedEventArgs class which is mine. The ChangedEventArgs class is a simple EventArgs class that looks like this:
public class BaseEventArgs : System.EventArgs
{
public bool Stop
{
get { return _Stop; }
set { _Stop = value; }
}
private bool _Stop = false;
public object Content
{
get { return _Content; }
set { _Content = value; }
}
private object _Content = null;
}
public class ChangedEventArgs : BaseEventArgs
{
}
Just a slightly modified EventArgs class. The other thing that you may notice about the vector class is it uses an EventHelper class to call the EventHandler. Once again, it's something that I created. Basically I was tired of writing the basic event raising code for every instance so I created a generic way of doing it.
public static class EventHelper
{
/// <summary>
/// Raises an event
/// </summary>
/// <typeparam name="T">The type of the event args</typeparam>
/// <param name="Delegate">The delegate</param>
/// <param name="Sender">The sender</param>
/// <param name="EventArgs">The event args</param>
public static void Raise<T>(EventHandler<T> Delegate, object Sender, T EventArg) where T : System.EventArgs
{
try
{
if (Delegate != null)
{
Delegate(Sender, EventArg);
}
}
catch { throw; }
}
}
It's pretty simple. Just takes in an EventHandler, the sender, and the eventargs. Even if all it does is saves me a couple lines of code in a couple other classes, that's all I really need. Anyway, that's it. With those classes we have our Vector class that can notify us when things are changed, we control how it grows, etc. along with a couple other functions/classes that you might find useful. So try it out, leave feedback, and happy coding.
14b1a3c0-0917-41c2-b95a-0003ff6ba9a2|0|.0