Problem:
You want your generic type to have a type parameter that supports members of an interface (such as the idisposable Interface) during creation.
Solution:
Use constraints to force generic type parameters to implement one or more specific interfaces.
Public class disposablelist <t>: ilist <t>
Where T: idisposable
{
Private list <t> _ items = new list <t> ();
// Private method that will dispose of items in the list
Private void Delete (T item)
{
Item. Dispose ();
}
}
This disposablelist class only allows objects that implement the idisposable interface to be passed as parameters. That's because every time youDisposablelistWhen deleting an object, you must call the dispose method. This allows you to easily manage objects in disposablelist.
The following code uses the disposablelist object:
Public static void testdisposablelistcls ()
{
Disposablelist <streamreader> DL = new disposablelist <streamreader> ();
// Create a few test objects.
Streamreader tr1 = new streamreader ("C: \ Boot. ini ");
Streamreader tr2 = new streamreader ("C: \ autoexec. Bat ");
Streamreader TR3 = new streamreader ("C: \ config. sys ");
// Add the test object to the disposablelist.
DL. Add (tr1 );
DL. insert (0, tr2 );
DL. Add (TR3 );
Foreach (streamreader Sr in dl)
{
Console. writeline ("sr. Readline () =" + Sr. Readline ());
}
// Call dispose before any of the disposable objects are
// Removed from the disposablelist.
DL. removeat (0 );
DL. Remove (tr1 );
DL. Clear ();
}
Discussion:
The where keyword is used to restrict type parameters and can only accept parameters that meet the given constraints. For example, disposablelist has a constraint that all types of parameter T must implement the idisposable interface:
Public class disposablelist <t>: ilist <t>
Where T: idisposable
This means that the following code will be compiled successfully:
Disposablelist <streamreader> DL = new disposablelist <streamreader> ();
But this won't work:
Disposablelist <string> DL = new disposablelist <string> ();
This is because string does not implement the idisposable interface, but streamreader does.
In addition to requiring one or more interfaces to be implemented, other constraints on type parameters are also allowed. You can require a type parameter to inherit from a specific base class, such as the textreader class:
Public class disposablelist <t>: ilist <t>
Where T: system. Io. textreader, idisposable
You can also constrain that this type parameter can only be a value type or a reference type. The constraint of the classes declared below is that they can only use value types:
Public class disposablelist <t>: ilist <t>
Where T: struct
However, only the reference type can be used:
Public class disposablelist <t>: ilist <t>
Where T: Class
In addition, you can also require any type of parameter to implement a common default constructor:
Public class disposablelist <t>: ilist <t>
Where T: idisposable, new ()
With constraints, you can write generic types that can only accept more specific and useful parameter types. If the idsiposable constraint is omitted in this example, a compilation error occurs. This is because not all types can be used as parameters of the disposablelist class that implements the idisposable interface. If you ignore this check during compilationDisposablelistObjects may contain objects that do not have a public, non-parameter dispose method. In this case, a runtime exception will occur. Generics and constraints require strict parameter type checks to some extent, which allows you to discover these problems during compilation, rather than runtime.