views:

130

answers:

4

Hi

I need to create an extension method to array class, but this extension method must be able to accept many data types, so it also must be generic.

In the code bellow the extension method just accept byte data type. I want it to also accept ushort and uint for instance. I believe that the best way to do that is creating a generic type here. But how can I do that using arrays?

Thanks!!!

public static class MyExtensions
{
    public static int GetLastIndex(this byte[] buffer)
    {
        return buffer.GetUpperBound(0);
    }
}
+9  A: 

Generics in extension methods aren't really anything special, they behave just like in normal methods.

public static int GetLastIndex<T>(this T[] buffer)
{
    return buffer.GetUpperBound(0);
}

As per your comment, you could do something like the following to effectively restrict the type of T (adding guard statements).

public static int GetLastIndex<T>(this T[] buffer) where T : struct
{
    if (!(buffer is byte[] || buffer is ushort[] || buffer is uint[]))
        throw new InvalidOperationException(
            "This method does not accept the given array type.");

    return buffer.GetUpperBound(0);
}

Note: As Martin Harris pointed out in a comment, you don't actually need to use generics here. The Array type from which all arrays derive will suffice.

If you want a more elegant solution, at the cost of slightly more code, you could just create overloads of the method:

public static int GetLastIndex(this byte[] buffer)
{
    return GetLastIndex(buffer);
}

public static int GetLastIndex(this ushort[] buffer)
{
    return GetLastIndex(buffer);
}

public static int GetLastIndex(this uint[] buffer)
{
    return GetLastIndex(buffer);
}

private static int GetLastIndex(Array buffer)
{
    return buffer.GetUpperBound(0);
}
Noldorin
@Noldorin: Thanks. Is it possible to make this method accept only the 3 data types byte, ushort and uint?
RHaguiuda
@RHaguiuda, if you want to support only byte, ushort, and uint, create method overloads for byte, ushort, and uint. Generics cannot be constrained to support only specific primitives.
Anthony Pegram
@RHaguiuda Anthony Pregram's approach is the correct one; overload the method. By using the generic approach, you could specify the following constraint to allow only value types as arguments for the type parameter: `public static int GetLastIndex<T>(this T[] buffer) where T : struct{...}`. You can't specify the types any further when working with generics (e.g. allow only `uint`, `byte`, and `ushort` as arguments for the type argument), so I'd recommend you to stick to Anthony Pregram's approach mentioned in the comment above.
Giu
@RHaguiuda: As others have said, unfortunately it's not possible to specifically constrain to these types (though you can do `where T : struct` to restrict to value types only). I've updated the post to show how manual type checks could be done; however, I do agree that creating overloads is probably cleaner, if a bit more work.
Noldorin
@Noldorin, @AnthonyPegram, @Giu - Thank you all guys for helping! Noldorin, could you update your answer adding code to Anthony suggestion on using overloads?
RHaguiuda
@RHaguiuda. Sure, it's quite straightforward. :)
Noldorin
@Noldorin: In the case of the 3-overload suggestion, isn't the overload that accepts an `Array` parameter kind of redundant? It seems like you're just introducing one more method call.
Dan Tao
@Dan: I've included it a) to show an alternative approach, b) because if the function gets any more complicated, refactoring as such may be appropiate. It's admittedly not necessary here, but oh well..
Noldorin
+4  A: 
public static class MyExtensions
{
    public static int GetLastIndex<T>(this T[] buffer)
    {
        return buffer.GetUpperBound(0);
    }
}
Albin Sunnanbo
+1 for also including the class declaration
gbogumil
+1  A: 

Same way you do generics in normal (non-extension) methods: Use a placeholder type name introduced in the generic syntax:

public static int GetLastIndex<TElement>(this TElement[] buffer)
Ben Voigt
A: 

@RHaguiuda

You can make constraint like

public static class MyExtensions{
public static int GetLastIndex<T>(this T[] buffer) where T: Integer
{
    return buffer.GetUpperBound(0);
}}

But, type used as a constraint must be an interface, a non-sealed class or a type parameter

Ehsan