I would go and encourage you to use Generics
instead of object
. When you use object
you're adding a casting operations in the back-scene, which means you might have a chance of getting casting exceptions at run-time. So, using generics would avoid that, and it would perform faster.
Also, in your code, you're using List
, which is fine, but why you don't benefit from the existed interfaces such as ICollection
, IList
..etc. These would give you many advantages, for instance, use ICollection
such as Sack<T> : ICollection<T>
you'll be able to use foreach
loop (because it implements IEnumerable
interfaces). So, make use of .NET existing interfaces, and don't take the long road.
Also, You can create an interface say ISack<T> : ICollection<T>
add the additional methods that you want, then do Sack<T> : ISack<T>
for your random index, you can declare the Random
and SelectedIndex
at the class level, and then create a method that returns a random index.
example :
public class Sack<T>
{
private readonly IList<T> objects = new List<T>();
private readonly Random rand = new Random();
private int SelectedIndex = -1;
public T Retrieve()
{
RandomIndex();
return objects[SelectedIndex];
}
public T Remove()
{
RandomIndex();
var removedObject = objects[SelectedIndex];
objects.Remove(removedObject);
return removedObject;
}
private void RandomIndex()
{
// keep creating a new random index until you get a non-null object.
// [ToDo] : what if object.Count == 0 ? how should you handle it ?
while (true)
{
if ((SelectedIndex == -1 || objects[SelectedIndex] == null))
{
SelectedIndex = rand.Next(0, objects.Count);
}
else
{
break;
}
}
}
}
I have added ICollection<T>
to the class, which would give you more options and customization
public class Sack<T> : ICollection<T>
{
private readonly IList<T> objects = new List<T>();
private readonly Random rand = new Random();
private int SelectedIndex = -1;
public T this[int index]
{
get => this[index];
set => this[index] = value;
}
public int Count => objects.Count;
public bool IsReadOnly => objects.IsReadOnly;
public void Add(T item)
{
objects.Add(item);
}
public void Clear() => objects.Clear();
public bool Contains(T item) => objects.Contains(item);
public void CopyTo(T[] array, int index) => objects.CopyTo(array, index);
public IEnumerator<T> GetEnumerator() => objects.GetEnumerator();
public int IndexOf(T item) => objects.IndexOf(item);
public void Insert(int index, T item) => objects.Insert(index, item);
public bool Remove(T item) => objects.Remove(item);
public void RemoveAt(int index) => objects.RemoveAt(index);
IEnumerator IEnumerable.GetEnumerator() => objects.GetEnumerator();
public T Retrieve()
{
RandomIndex();
return objects[SelectedIndex];
}
public T Remove()
{
RandomIndex();
var removedObject = objects[SelectedIndex];
objects.Remove(removedObject);
return removedObject;
}
private void RandomIndex()
{
while (true)
{
if ((SelectedIndex == -1 || objects[SelectedIndex] == null))
{
SelectedIndex = rand.Next(0, objects.Count);
}
else
{
break;
}
}
}
}
}
There are no concrete uses for this class
. could make this question off-topic. We are looking for real code that does something and generally an explanation of what the code does. \$\endgroup\$Retrieve()
method doesn't remove the item from the sack. If you're trying to disagree with me, then you've mistakenly proven my point that the method names are poor by making the very mistake I described. \$\endgroup\$