Why not inherit from ListT?
There are some good answers here. I would add to them the following points.
What is the correct C# way of representing a data structure, which, "logically" (that is to say, "to the human mind") is just a list of things with a few bells and whistles?
Ask any ten non-computer-programmer people who are familiar with the existence of football to fill in the blank:
A football team is a particular kind of _____
Did anyone say "list of football players with a few bells and whistles", or did they all say "sports team" or "club" or "organization"? Your notion that a football team is a particular kind of list of players is in your human mind and your human mind alone.
List<T>
is a mechanism. Football team is a business object -- that is, an object that represents some concept that is in the business domain of the program. Don't mix those! A football team is a kind of team; it has a roster, a roster is a list of players. A roster is not a particular kind of list of players. A roster is a list of players. So make a property called Roster
that is a List<Player>
. And make it ReadOnlyList<Player>
while you're at it, unless you believe that everyone who knows about a football team gets to delete players from the roster.
Is inheriting from
List<T>
always unacceptable?
Unacceptable to whom? Me? No.
When is it acceptable?
When you're building a mechanism that extends the List<T>
mechanism.
What must a programmer consider, when deciding whether to inherit from
List<T>
or not?
Am I building a mechanism or a business object?
But that's a lot of code! What do I get for all that work?
You spent more time typing up your question that it would have taken you to write forwarding methods for the relevant members of List<T>
fifty times over. You're clearly not afraid of verbosity, and we are talking about a very small amount of code here; this is a few minutes work.
UPDATE
I gave it some more thought and there is another reason to not model a football team as a list of players. In fact it might be a bad idea to model a football team as having a list of players too. The problem with a team as/having a list of players is that what you've got is a snapshot of the team at a moment in time. I don't know what your business case is for this class, but if I had a class that represented a football team I would want to ask it questions like "how many Seahawks players missed games due to injury between 2003 and 2013?" or "What Denver player who previously played for another team had the largest year-over-year increase in yards ran?" or "Did the Piggers go all the way this year?"
That is, a football team seems to me to be well modeled as a collection of historical facts such as when a player was recruited, injured, retired, etc. Obviously the current player roster is an important fact that should probably be front-and-center, but there may be other interesting things you want to do with this object that require a more historical perspective.
Inheriting from ListT
If you want to create a publicly exposed animal collection you should not inherit from List<T>
and instead inherit from Collection<T>
and use the postfix Collection
in the class name. Example: AnimalCollection : Collection<Animal>
.
This is supported by the framework design guidelines, more specifically:
DO NOT use
ArrayList
,List<T>
,
Hashtable
, orDictionary<K,V>
in
public APIs. UseCollection<T>
,
ReadOnlyCollection<T>
,
KeyedCollection<K,T>
, or
CollectionBase subtypes instead. Note
that the generic collections are only
supported in the Framework version 2.0
and above.
Inheriting ListT to implement collections a bad idea?
I wouldn't inherit from List<T>
- it introduces issues like these, and doesn't really help (since there are no virtual
methods to override). I would either use List<T>
(or the more abstract IList<T>
), or to introduce polymorphism Collection<T>
has virtual methods.
As a note; re things like FindAll
, you may also find the LINQ options (like .Where()
) useful counterparts; most notably, they will work for any IList<T>
(or IEnumerable<T>
), not just List<T>
and subclasses.
Question inheriting from List(of T) class
Your issue is that you're both inheriting from List(of T)
and you have an instance property of that type, which is where you're storing your data. When Count
is called in your above code, it's using the Count
property from your parent List(of T)
, which isn't where you're storing your data.
A better idea would be for you to inherit from object
and have PriorityQueue(of T)
implement ICollection
and IEnumerable(of T)
explicitly. You shouldn't have to change your internal implementation at all, you'll just have to add code to support those interfaces.
Inheriting from ListT in .NET (vb or C#)
You said:
I have a class called 'Person' and I
need a collection called 'Scouts',
which I want in an Class called
'Scouts', at this point I'd like to be
able to write
foreach Person in Scouts ...
If I understand you correctly, you want:
class Scouts : IEnumerable<Person>
{
private List<Person> scouts;
public IEnumerator<Person> GetEnumerator()
{
return scouts.GetEnumerator();
}
}
C# Adding Current property to a list class inheriting from listT
There's a few options on how to do this. As you're just starting out, I'd say use option 1 as this is a lot simpler.
Option 1: Basic using LINQ
Below is a Volume
class and a Main
method which shows examples of usage. You can use Linq to get the first/last items in the list of volumes and then you can set properties on individual items in the list by using volumes[i]
where i
is the index of the item in the list.
You can also use Linq to find particular volumes based on Color
, Name
, HasVolume
and then change properties on each of those using a foreach
loop.
More info on LINQ is here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/.
Take a look at the example below:
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
var volumes = new List<Volume>();
var volume1 = new Volume("vol1", "red", true);
var volume2 = new Volume("vol2", "red", true);
volumes.Add(volume1); //adds the first volume
volumes.Add(volume2); //adds the second volume
var lastVolume = volumes.First(); //gets the first volume
var firstVolume = volumes.Last(); //gets the last volume
volumes[0].Color = "blue"; //sets the first volume color to blue
volumes[1].Color = "green"; //sets the second volume color to green
// set all green volumes to purple
var greenVolumes = volumes.Where(v => v.Color == "green");
foreach (var greenVolume in greenVolumes)
{
greenVolume.Color = "purple";
}
}
}
public class Volume
{
public string Name { get; set; }
public string Color { get; set; }
public bool HasSegment { get; set; }
public Volume(string name, string color, bool hasSegment)
{
Name = name;
Color = color;
HasSegment = hasSegment;
}
}
}
Option 2: More advanced using the Iterator pattern
Take a look at the iterator pattern here: https://www.dofactory.com/net/iterator-design-pattern.
Basically, it will allow you to step through the list by selecting MoveNext()
, Last
, First
, and Current
. I've added a _current
field which keeps track of which item you are working with. It relates to the index of the collection/list.
using System.Collections.Generic;
namespace WebApplication1.Sandbox
{
public class Volume
{
public string Name { get; set; }
public string Color { get; set; }
public bool HasSegment { get; set; }
public Volume(string name, string color, bool hasSegment)
{
Name = name;
Color = color;
HasSegment = hasSegment;
}
}
public class Iterator<T>
{
private readonly List<T> _items;
private int _index;
public T Last
{
get => _items[_items.Count - 1];
set => _items[_items.Count - 1] = value;
}
public T First
{
get => _items[0];
set => _items[0] = value;
}
public T Current
{
get => _items[_index];
set => _items[_index] = value;
}
public Iterator(List<T> items)
{
_items = items;
}
public bool MoveNext()
{
if (_index == _items.Count - 1)
{
return false;
}
else
{
_index++;
return true;
}
}
}
}
Now you can use it like in this unit test:
[Fact]
public void VolumeIteratorGetsNextThenSetsCurrentByProperty()
{
var sut = new Iterator<Volume>(_volumes);
sut.MoveNext();
sut.Current.Name = "vol2modifiedAgain";
Assert.Equal("vol2modifiedAgain", sut.Current.Name);
}
Unit tests are here:
using System.Collections.Generic;
using WebApplication1.Sandbox;
using Xunit;
namespace WebApplication1.Tests
{
public class VolumeIteratorTests
{
private List<Volume> _volumes => new List<Volume>()
{
new Volume("vol1", "green", true),
new Volume("vol2", "green", true)
};
[Fact]
public void VolumeIteratorGetsCurrent()
{
var sut = new Iterator<Volume>(_volumes);
Assert.Equal("vol1", sut.Current.Name);
}
[Fact]
public void VolumeIteratorGetsNext()
{
var sut = new Iterator<Volume>(_volumes);
sut.MoveNext();
Assert.Equal("vol2", sut.Current.Name);
}
[Fact]
public void VolumeIteratorGetsNextThenSetsCurrent()
{
var sut = new Iterator<Volume>(_volumes);
sut.MoveNext();
sut.Current = new Volume("vol2modified", "green", false);
Assert.Equal("vol2modified", sut.Current.Name);
}
[Fact]
public void VolumeIteratorGetsNextThenSetsCurrentByProperty()
{
var sut = new Iterator<Volume>(_volumes);
sut.MoveNext();
sut.Current.Name = "vol2modifiedAgain";
Assert.Equal("vol2modifiedAgain", sut.Current.Name);
}
[Fact]
public void VolumeIteratorGetsLast()
{
var sut = new Iterator<Volume>(_volumes);
Assert.Equal("vol2", sut.Last.Name);
}
[Fact]
public void VolumeIteratorSetsLast()
{
var sut = new Iterator<Volume>(_volumes);
sut.Last = new Volume("last", "red", true);
Assert.Equal("last", sut.Last.Name);
}
[Fact]
public void VolumeIteratorGetsFirst()
{
var sut = new Iterator<Volume>(_volumes);
Assert.Equal("vol1", sut.First.Name);
}
[Fact]
public void VolumeIteratorSetsFirst()
{
var sut = new Iterator<Volume>(_volumes);
sut.First = new Volume("first", "red", true);
Assert.Equal("first", sut.First.Name);
}
[Fact]
public void MoveNextReturnsTrueIfNotLastItem()
{
var sut = new Iterator<Volume>(_volumes);
Assert.True(sut.MoveNext());
}
[Fact]
public void MoveNextReturnsFalseIfLastItem()
{
var sut = new Iterator<Volume>(_volumes);
sut.MoveNext();
Assert.False(sut.MoveNext());
}
}
}
Related Topics
Add CSS Class to a Div in Code Behind
Applying CSS on ASP.NET Fileupload Control's Browse Button Only
ASP.NET Page Is Not Loading CSS Styles
Can a Web User Control (.Ascx) Use a CSS File for Styling
Minifying and Combining Files in .Net
Add Search Functionality on Dropdownlistfor
Asp:Fileupload Edit "No File Selected" Message
HTML Table (Text) to Image Using C#
Using C# to Dynamically Generate CSS Files
Send Push to Android by C# Using Fcm (Firebase Cloud Messaging)
Adding Distance to a Gps Coordinate
How to Manage Files on an Mtp Portable Device
Xamarin iOS Memory Leaks Everywhere
How to Add a Custom View to a Xib File Defined View in Monotouch
Executing R Script Programmatically
In Ruby, What Is the Equivalent to an Interface in C#
How to Redirecttoaction in ASP.NET MVC Without Losing Request Data