I want to write a generic function that has a constraint on the type. Specifically I want something like this:
bool IsInList<T>(T value, params T[] args)
{
bool found = false;
foreach(var arg in args)
{
if(arg == value)
{
found = true;
break;
}
}
return found;
}
The point being that you can check if an item is in a parameter list viz:
if(IsInList("Eggs", "Cheese", "Eggs", "Ham"))
However, the compiler croaks on the equality line. So I want to put in a constraint on the type that it implements IEquatable. However, constraints only seem to work at the class level. Is this correct, or is there some way to specify this generically?
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>
.
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