(Update – from comments) Question: Is there any advantage of using one extension method over the other?
From a discussion that I am having in my codeproject article on extension methods, I am unsure whether the following is correct or not.
Currently, I have the following extension method:
public static bool In<T>(this T source, params T[] list)
{
if (null == source) throw new ArgumentNullException("source");
return list.Contains(source);
}
Which works as expected. It has been suggested in the comments that I change it so that it only checks reference types like so:
public static bool In<T>(this T source, params T[] list)
{
if (!typeof(T).IsValueType)
{
if (Equals(source, default(T))) throw new ArgumentNullException("source");
}
return list.Contains(source);
}
Again that works as expected. Is there any advantage of the second method over the first given that running a quick benchmark, we are talking about 0.001 of a second difference for 10000 runs.
Output of benchmark (Core i3 @ 4ghz, RAID 0 ssd’s):
Testing performance...
Value type, original: 00:00:00.0033289
Value type, from code project: 00:00:00.0033027
Reference type, original: 00:00:00.0076951
Reference type, from code project: 00:00:00.0068459
Benchmark code:
Console.WriteLine("Testing performance...");
Console.WriteLine("");
const Int32 _runs = 10000;
Stopwatch sw = new Stopwatch();
Console.Write("Value type, original: ");
sw.Start();
for (Int32 i = 0; i < _runs; i++)
{
try
{
i.In(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
}
catch (Exception)
{
// do nothing
}
}
sw.Stop();
Console.WriteLine(sw.Elapsed.ToString());
sw = new Stopwatch();
Console.Write("Value type, from code project: ");
sw.Start();
for (Int32 i = 0; i < _runs; i++)
{
try
{
i.In2(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
}
catch (Exception)
{
// do nothing
}
}
sw.Stop();
Console.WriteLine(sw.Elapsed.ToString());
sw = new Stopwatch();
Console.Write("Reference type, original: ");
sw.Start();
for (Int32 i = 0; i < _runs; i++)
{
try
{
"This String".In("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
}
catch (Exception)
{
// do nothing
}
}
sw.Stop();
Console.WriteLine(sw.Elapsed.ToString());
sw = new Stopwatch();
Console.Write("Reference type, from code project: ");
sw.Start();
for (Int32 i = 0; i < _runs; i++)
{
try
{
"This String".In("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
}
catch (Exception)
{
// do nothing
}
}
sw.Stop();
Console.WriteLine(sw.Elapsed.ToString());
Console.WriteLine("");
Console.ReadLine();
public static bool In<T>(this T source, params T[] list)
{
if (source == null) throw new ArgumentNullException("source");
return list.Contains(source);
}
public static bool In2<T>(this T source, params T[] list)
{
if (!typeof(T).IsValueType)
{
if (Equals(source, default(T))) throw new ArgumentNullException("source");
}
return list.Contains(source);
}
I would leave your code as
because it is easier to read.
On a related note: can source ever be a value type? If not you could constrain T as
T:class.