Others have mentioned IEquatable<T>
which is certainly a good potential constraint.
Another option to remember is EqualityComparer<T>.Default
, which will use IEquatable<T>
if available, but fall back to object.Equals(object)
otherwise. This means you can use it with types which predate generics but override Equals
, for example:
bool IsInList<T>(T value, params T[] args)
{
IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
bool found = false;
foreach(var arg in args)
{
if(comparer.Equals(arg, value))
{
found = true;
break;
}
}
return found;
}
Note that the default equality comparer also copes with null references, so you don't need to worry about those yourself. If type T
hasn't overridden object.Equals(object)
or implemented IEquatable<T>
, you'll get reference equality semantics (i.e. it will only return true
if the exact reference is in the array).
A few other points:
Your desire to stick to a single exit point makes the code less readable, IMO. There's no need for an extra variable here:
bool IsInList<T>(T value, params T[] args)
{
IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
foreach (var arg in args)
{
if (comparer.Equals(arg, value))
{
return true;
}
}
return false;
}
LINQ already contains a method for this, Contains
, so you can simplify the code to:
bool IsInList<T>(T value, params T[] args)
{
return args.Contains(value);
}
Array
effectively contains this functionality too, with IndexOf
:
bool IsInList<T>(T value, params T[] args)
{
return Array.IndexOf(args, value) != -1;
}
Your method is perhaps a little misleadingly named, given that args
is an array, not a List<T>
.