Creating a simple list (UniqueList) of items with a Name property that must only contains unique items (defined as having different Names). The constraint on the UniqueList type can be an interface:
interface INamed
{
string Name { get;}
}
or an abstract class:
public abstract class NamedItem
{
public abstract string Name { get; }
}
So the UniqueList can be:
class UniqueList<T> : List<T> where T : INamed
or
class UniqueList<T> : List<T> where T : NamedItem
The class function, AddUnique:
public T AddUnique(T item)
{
T result = Find(x => x.Name == item.Name);
if (result == default(T))
{
Add(item);
return item;
}
return result;
}
If the class type constraint is based on the interface, compiling results in
Error: Operator '==' cannot be applied to operands of type 'T' and 'T'
at the line
if (result == default(T))
All is well if I base UniqueList on the abstract class. Any thoughts?
Interface Type Constraint You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter.
A type constraint on a generic type parameter indicates a requirement that a type must fulfill in order to be accepted as a type argument for that type parameter. (For example, it might have to be a given class type or a subtype of that class type, or it might have to implement a given interface.)
No, and it would be pointless to do so. If you didn't declare the parameters, you wouldn't be able to call the method given only a reference to the base class.
That's because the interface can be applied to a struct which is a value type. To make it work with the interface extend the constraint like this:
class UniqueList<T> : List<T> where T : INamed, class
That will make sure you won't be able to pass a struct as T
and hence default(T)
will evaluate to null
which is what you expect.
Also, I'd recommend generalizing your UniqueList
a bit, allowing for different types of unique keys:
interface IUnique<TKey>
{
TKey UniqueKey { get;}
}
class UniqueList<TItem,Tkey> : List<TItem> where TItem : IUnique<TKey>, class
Then the INamed
interface can be easily declared as:
interface INamed : IUnique<string>
{
string Name { get;}
}
UniqueKey
or Name
would be implmeneted explicitly in the implementing class to prevent unnecessary (duplicate in fact) public class members.
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