I have a function which returns a variable number of elements, should I return an array or a List? The "collection's" size does not change once returned, ie for all purposes the collection is immutable. I would think to just return an array, but some people have said to not return variable sized arrays from a function as it is "poor form". Not sure why?
Does it matter that this needs to be .NET 2.0 compliant?
C programming does not allow to return an entire array as an argument to a function. However, you can return a pointer to an array by specifying the array's name without an index.
C returns by value. Arrays cannot be passed by value, therefore they cannot be returned.
Arrays returned by properties are not write-protected, even if the property is read-only. To keep the array tamper-proof, the property must return a copy of the array. Typically, users won't understand the adverse performance implications of calling such a property.
It's bad form to return arrays if not needed, and especially to return List<T>
.
Usually, you'll want to return IEnumerable<T>
or IList<T>
.
If your user is going to just need to run through each element, IEnumerable<T>
will provide this capability. It also allows you to potentially implement the routine (now or later) using deferred execution.
If your user needs to access elements by index, return IList<T>
. This provides all of the benefits of arrays, but gives you more flexibility in your implementation. You can implement it as an array, a list, or some other collection that implements IList<T>
, and you don't have to convert/copy to an array.
One opinion I see pretty often a suggestion to return either IList<T>
or ReadOnlyCollection<T>
. It's OK to return these if you have one of these available - both can be assigned directly to an IEnumerable<T>
(they work directly with any LINQ methods). One thing to note is ReadOnlyCollection<T>
is a very lightweight type that can wrap any IList<T>
.
Expanding on Reed's answer.
Eric Lippert did a great blog post on this very subject. It's got probably the most detailed answer available
Return IEnumerable
unless you need:
IReadOnlyCollection
. BenchmarkDotNet=v0.10.8, OS=Windows 10 Redstone 1 (10.0.14393) Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4 Frequency=3233538 Hz, Resolution=309.2588 ns, Timer=TSC [Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1648.0 Clr : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1648.0 Core : .NET Core 4.6.25211.01, 64bit RyuJIT
Method | Job | Runtime | Mean | Error | StdDev | Min | Max | Median | Rank | Allocated |
---------- |----- |-------- |-----------:|-----------:|----------:|-----------:|-----------:|-----------:|-----:|----------:|
TestList | Clr | Clr | 5,153.3 ns | 34.002 ns | 31.806 ns | 5,119.2 ns | 5,213.4 ns | 5,135.9 ns | 3 | 0 B |
TestArray | Clr | Clr | 730.1 ns | 6.962 ns | 6.512 ns | 722.4 ns | 743.9 ns | 729.5 ns | 2 | 0 B |
TestList | Core | Core | 5,188.4 ns | 102.816 ns | 96.174 ns | 5,070.3 ns | 5,342.6 ns | 5,185.6 ns | 3 | 0 B |
TestArray | Core | Core | 709.0 ns | 6.126 ns | 5.730 ns | 700.8 ns | 718.6 ns | 708.1 ns | 1 | 0 B |
Code:
[RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn]
[ClrJob, CoreJob]
[HtmlExporter, MarkdownExporter]
[MemoryDiagnoser]
public class BenchmarkForEach
{
List<string> testData = new List<string>();
string[] testArray;
public BenchmarkForEach()
{
for(int i=0;i<1000;i++)
{
testData.Add(i.ToString());
}
testArray = testData.ToArray();
}
[Benchmark]
public int TestList()
{
var x = 0;
foreach(var i in testData)
{
x += i.Length;
}
return x;
}
[Benchmark]
public int TestArray()
{
var x = 0;
foreach (var i in testArray)
{
x += i.Length;
}
return x;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With