If I had to guess, I'd say that this developer was used to some other language like Java, and wasn't fully aware of standard practice in C#. The "get[Property]" nomenclature is very heavily used in Java, javascript, etc. C# replaces this with properties and indexers. Properties are every bit as powerful as getters and setters, but are easier to write and use. The only time you typically see "Get[something]" in C# is if:
- The operation is likely to be expensive enough that you really want to drive home the fact that this is no simple member access (e.g.
GetPrimeNumbers()
), or
- Your collection actually includes multiple indexed collections. (e.g.
GetRow(int i)
and GetColumn(int i))
. Even in this case, it's more common to simply expose each of these indexed collections as a property unto itself, which is of an indexed type ("table.Rows[2]
").
If you are only accessing these values in for
loops, the collection should implement IEnumerable<Thing>
, which would give you access to LINQ methods and the foreach
construct. If you still need to have indexed-based getters, you should consider using your own interface which extends IEnumerable<T>
, but additionally provides:
T this[int i] { get; }
This way, you don't give consumers the impression that they can Add
and Remove
objects in this collection.
Update
I know this is mostly a matter of style, which is subject to debate, but I really think the GetThings
solution is not the correct way to do things. The following strategy, while it takes a little more work, is far more in keeping with the way that the standard .NET classes and frameworks are designed:
public class ThingHolderDataAccess
{
public ThingHolder GetThingHolderForSomeArgs(int arg1, int arg2)
{
var oneThings = GetOneThings(arg1);
var otherThings = GetOtherThings(arg2);
return new ThingHolder(oneThings, otherThings);
}
private IEnumerable<OneThing> GetOneThings(int arg)
{
//...
return new List<OneThing>();
}
private IEnumerable<AnotherThing> GetOtherThings(int arg2)
{
//...
return new List<AnotherThing>();
}
}
public class ThingHolder
{
public IIndexedReadonlyCollection<OneThing> OneThings
{
get;
private set;
}
public IIndexedReadonlyCollection<AnotherThing> OtherThings
{
get;
private set;
}
public ThingHolder(IEnumerable<OneThing> oneThings,
IEnumerable<AnotherThing> otherThings)
{
OneThings = oneThings.ToIndexedReadOnlyCollection();
OtherThings = otherThings.ToIndexedReadOnlyCollection();
}
}
#region These classes can be written once, and used everywhere
public class IndexedCollection<T>
: List<T>, IIndexedReadonlyCollection<T>
{
public IndexedCollection(IEnumerable<T> items)
: base(items)
{
}
}
public static class EnumerableExtensions
{
public static IIndexedReadonlyCollection<T> ToIndexedReadOnlyCollection<T>(
this IEnumerable<T> items)
{
return new IndexedCollection<T>(items);
}
}
public interface IIndexedReadonlyCollection<out T> : IEnumerable<T>
{
T this[int i] { get; }
}
#endregion
Using the code above might look something like this:
var things = _thingHolderDataAccess.GetThingHolderForSomeArgs(a, b);
foreach (var oneThing in things.OneThings)
{
// do something
}
foreach (var anotherThing in things.OtherThings)
{
// do something else
}
var specialThing = things.OneThings[c];
// do something to special thing