Generics and arrays - type specific operations
Written by Mike James   
Tuesday, 01 March 2011
Article Index
Generics and arrays - type specific operations



Along with the generic versions of Sort, other useful generic methods were introduced along with generics including Find, FindAll, FindIndex, FindLast and FindLastIndex, LastIndexOf, TrueForAll, ConvertAll.

Once you have seen how the Find method works the rest are easy to understand. The Find method returns the array element that satisfies a condition, it is defined as:    

public static T Find<T> ( 
T[] array,
      Predicate<T> match

The Predicate delegate function is defined as:

public delegate bool Predicate<T> (
      T obj

From these you can probably work out how to use Find correctly.

For example, to pick out the first negative value in the array we first need a suitable predicate with the correct generic signature:

public bool MyLess(int x)
return (x < 0);

Notice that this implies that T is int.


Now we can return the first negative value in the array using:

int result=Array.Find(A, MyLess);

If having to introduce an explicit method, e.g. MyLess, is something you would rather avoid then you could use an anonymous delegate:

int result = Array.Find(A,
delegate(int x) { return (x < 0); });

The same thing works for all of the generic methods.

For example:

Array.Sort(A, delegate(int x, int y)
{return (((int)y).CompareTo((int)x)); });

Notice that there are some generic methods that need you to specify the types because the compiler cannot work them out from the context.

For example, the very useful ConvertAll can be used to implement custom conversion from one array type to another. To convert from Int32 to Int64 you would write:

public Int64 MyConvert(Int32 input)
return (Int64)input;

So far nothing new, but to call the ConvertAll method you need to write:

Int64[] B = Array.ConvertAll<Int32, Int64>(
A, MyConvert);

You can’t drop the <Int32,Int64> type definition because it’s just too difficult for the compiler to work out.

To generalize the pattern

In summary, the generic methods make working with arrays and collections in general much easier because they allow you to pass in generic methods which perform type specific operations - compare, fid convert and so on.

You can use this approach in general situations where you need to implement a generic algorithm but with type specific methods. Simply pass in the type specific operation as a generic delegate and provide a concrete implementation of the method when you call the generic method.  For example, if you need to write a generic method that adds generic types you would pass in a generic Add delegate that provided the type specific implementation.

For example, the generic method would be something like:

public MyGenericMethod<T> (
 T a, T b,     
Addmethod<T> add )
T c=add(a,b);

Notice that the add method is a type dependent operation.

To make this work the Addmethod generic delegate would be something like:


public delegate T Addmethod<T> (T x,T y)


And following this you could define an Addmethod for integers as:

int Adder(int x,int y)
return x+y;

and you could call the generic method customised for integers as:

public MyGenericMethod<int> (a,b,Adder)

It is something of a chore to have to package the type specific operation in a delegate each time you want to use the generic method but lambda expressions make it less painful.



Deep C# - Casting the Escape from Strong Typing

Casting is one of the most confusing aspects of any modern language and it often makes beginners think hard. But if you know why you are doing it, then the how makes a lot more sense. We have encounte [ ... ]

Deep C# - Interface

Interfaces - what are they for? Not quite inheritance yet they seem to fit the same purpose. Find out in this extract from my new book, Deep C#: Dive Into Modern C#.

Other Articles






Last Updated ( Tuesday, 01 March 2011 )