Other Generic Framework Types C# Help

In addition to the System. Collections. Generic namespace, the .NET Framework has other uses for generic types. The structs and delegates discussed here are all in the System namespace and serve different purposes.

This section discusses the following:

  1.  The struct Nullable<T>
  2.  The delegate EventHandler<TEventArgs>
  3.  ThestructArraySegment<T>

Nullable<T>

A number in a database and a number in a programming language have an important difference in their characteristics, as a number in the database can be null. A number in C# cannot be null. Int32 is a struct, and because structs are implemented as value types, they cannot be null.

The problem doesn’t exist only with databases but also with mapping XML data to .NET types.

This difference often causes headaches and lot of additional work to map the data. One solution is to map numbers from databases and XML files to reference types, because reference types can have a null value. However, this also means additional overhead during runtime.

With the structure Nullable~T> this can be easily resolved. In the example, Nullable<T> is instantiated with Nullablednt>. The variable x can now be used like an int, assigning values and using operators to do some calculation. This behavior is made possible by casting operators of the Nullable<T> type. However, x can also be null. The Nullable<T> properties Has Value and Value can check if there is a value, and the value can be accessed:

Nullable<int> x;
x = 4;
x += 3;
if (x.1iasValue)
{
int y = x.Value;
x = null;

}

Because nullable types are used very often, C# has a special syntax for defining variables of this type. Instead of using the syntax with the generic structure, the ? operator can be used. In the following example, the variables xl and x2 both are instances of a nullable int type:

Nullable<int> xl;
int? x2;

A nullable type can be compared with null and numbers as shown. Here, the value of x is compared with null, and if it is not null, it is compared with a value smaller than 0:

int? x = GetNullableType();if (x == null)
(
Console.WriteLine(‘x is null’);
)
else if (x'< 0)
(  .
ConsoJe.writeLine{‘x is smaller· thAn O’);

}

Nullable types can also be used with arithmetic operators. The variable x3 is the sum of the variables xl and x2.If any of the nullable types has a null value, the result is null:

int? xl : GetNullableType();
int? x2 = GetNullableType();
int? x3 : xl + x2;

The method GetNullableType ()that is called here is just a place holder for any method that returns a nullable into For testing you can implement it as simple to return null or to return any integer value.

Non-nullable types can be converted to nullable types. With the conversion from a non-nullable type to a nullable type, an implicit conversion is possible where casting is not required. This conversion always succeeds:

int yl = 4;
int? xl : yl;

The other way around, the conversion from a nullable type to a non-nullable type, can fail. If the nullable type has a jlullvalue and the null value is assigned to a non-nullable type, an exception of type InvalidOperationException is thrown. That’s the reason the cast operator is required to do an explicit conversion:

int? xl = GetNullableType();
int yl = (int)xl;

Instead of doing an explicit cast, it is also possible to convert a nullable type to a non-nullable type with the coalescing operator, The coalescing operator has the syntax?? to define a default value for the conversion in case the nullable type has a value of null. Hence you gets the value 0 if xl is null:

int? xl =”GetNullableType();
int yl = xl ?? 0;

Event Handler <TEventArgs>

 With Windows Forms and Web applications, delegates for many different event handlers are defined. Some of the event handlers are listed here:

public sealed delegate void EventHandler(object sender, EventArgs e);
public sealed delegate void PaintEventHandler(object sender,
PaintEventArgs e);
public sealed delegate void MouseEventHandler(object sender,
MouseEventArgs e);

These delegates have in common that the first argument is always the sender, who was the origin of the event, and the second argument is of a type to contain information specific to the event.

With the new EventHandler<TEventArgs>, it is not necessary to define a new delegate for every event handler. As you can see, the first parameter is defined the same way as before, but the second parameter is a generic type TEventArgs. The where clause specifies that the type for TEventArgs must be derived from the base class EventArgs:

public sealed delegate void EventHandler<TEventArgs> (object sender,
TEventArgs e)
where TEventArgs : EventArgs

Array Segment <T>

The struct ArraySegment<T> represents a segment of an array. If parts of an array are needed, a segment can be used. With the struct ArraySegrnent<T>, the information about the segment (the offset and count) is contained within this structure.

In the example, the variable arr is defined as an int array with eight elements. The variable segment of type ArraySegment<int> is used to represent a segment of the integer array. The segment is initialized with the constructor, where the array is passed together with an offset and an item count. Here, the offset is set to 2, so you start with the third element, and the count is set to 3, so 6 is the last element of the segment.

The array behind the array segment can be accessed with the Array property. ArraySegment<T> also has the properties Offset and Count that indicate the initialized values to define the segment. The for loop is used to iterate through the array segment. The first expression of the for loop is initialized to the offset where the iteration should begin. With the second expression, the count of the element numbers in the segment is used to check if the iteration should stop. Within the for loop, the elements contained by the segment are accessed with the Array property:

int() arr = (1, 2, 3, 4, 5, 6, 7, 8);
ArraySegment<int> segment = new ArraySegment<int> (arr. 2. 3);
for (int ~ = segment.Offset; i < segment.Offset + segment.Count; i++)
( …
Console.WriteLine(segment.Array(i) };

}

With the example so far, you might question the usefulness of the ArraySegment<T> structure. However, the ArraySegment<T> can also be passed as an argument to methods. This way, just a single argument is needed instead of three that define the offset and count in addition to the array.

The method WorkWithSegment () gets an ArraySegrnent<string> as a parameter. In the implementation of !his method, the properties Offset, Count, and Array are used as before:

void WorkWithSegment(ArraySegment<string> segment)
{
for (int i = segment.Offset; i < segment.Offset + segment.Count; i++)
(
Console.WriteLine(segment.Array(i);

)

}

It’s important to note that array segments don’t copy the elements of the originating array. Instead, the originating array can be accessed through ArraySegment<T>. If elements of the array segment are changed, the changes can be seen in the original array.

Summary

This chapter introduced a very important feature of the CLR 2.0 generics. With generic classes you can create type-independent classes, and generic methods allow type-independent methods. Interfaces, structs, and delegates can be created in a generic way as well. Generics make new programming styles possible. You’ve seen how algorithms, particularly actions and predicates, can be implemented to be used with different classes – and all type-safe. Generic delegates make it possible to decouple algorithms from -collections.

Other .NET Framework types include Nullable<T>, EventHandler <TEventArgs>, and
ArraySegment <T>.

Posted on October 29, 2015 in Generics

Share the Story

Back to Top
Share This