I found this method:
public async Task SomeMethod(IEnumerable<Member> members)
{
await DoSomething(members.First());
await DoSomethingElse(members.First());
}
It's being called like this:
List<Member> members = GetMembers();
await SomeMethod(members);
I know this could be particularly bad if GetMembers()
returned an IQueryable<Member>
, but since it's just a List<Member>
, is it still bad to call First()
twice like that?
Is it best practice to call First()
once and store the result in a variable?
First
function in System.Linq.Enumerable
In System.Linq.Enumerable
here's how First
function was implemented:
public static TSource First<TSource>(this IEnumerable<TSource> source)
{
TSource? first = source.TryGetFirst(out bool found);
if (!found)
{
ThrowHelper.ThrowNoElementsException();
}
return first!;
}
TryGetFirst
was called, let's have a look:
private static TSource? TryGetFirst<TSource>(this IEnumerable<TSource> source, out bool found)
{
if (source is null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
return
#if !OPTIMIZE_FOR_SIZE
source is Iterator<TSource> iterator ? iterator.TryGetFirst(out found) :
#endif
TryGetFirstNonIterator(source, out found);
}
Then TryGetFirstNonIterator
was called, let's have a look:
private static TSource? TryGetFirstNonIterator<TSource>(IEnumerable<TSource> source, out bool found)
{
if (source is IList<TSource> list)
{
if (list.Count > 0)
{
found = true;
return list[0];
}
}
else
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
if (e.MoveNext())
{
found = true;
return e.Current;
}
}
}
found = false;
return default;
}
As we can see, it does return list[0] if the soruce is IList<TSource>
.
Source Code
SomeMethod
Regardless of how First
was implemented. The question you asked:
I know this could be particularly bad if GetMembers() returned an IQueryable, but since it's just a List, is it still bad to call First() twice like that? Is it best practice to call First() once and store the result in a variable?
I think overloading is all you need.
public async Task SomeMethod(Member member)
{
await DoSomething(member);
await DoSomethingElse(member);
}
public async Task SomeMethod(IEnumerable<Member> members)
{
await SomeMethod(members.First());
}