views:

227

answers:

3

I would like to convert T to T[] if it is an array.

static T GenericFunction<T>(T t)
{
       if (t == null) return default(T);

       if (t.GetType().IsArray)
       {
            //if object is an array it should be handled
            //by an array method
            return (T) GenericArrayFunction((T[])t); 
       }
       ...
}

static T[] GenericArrayFunction<T>(T[] t)
{
       if (t == null) return default(T);

       for (int i = 0 ; i < t.Length ; i++) 
       {
            //for each element in array carry
            //out Generic Function
            if (t[i].GetType().IsArray())
            {
                 newList[i] = GenericArrayFunction((T[])t[i]); 
            }
            else
            {
                 newList[i] = GenericFunction(t[i]);
            }
       }
       ...
}

Error If I try (T[])t

Cannot convert type 'T' to 'T[]'

Error If I just try to pass t

The type arguments for method 'GenericArrayFunction(T[])' cannot be inferred from the usage. Try specifying the type arguments explicitly.

+3  A: 

Just because T is an array type doesn't mean that it's also an array of T. In fact, the only way that could happen would be for T to be something like object, Array or one of the interfaces implemented by arrays.

What are you really trying to do? I suspect you want to find out the element type of the array, and then call GenericArrayFunction with the appropriate T - but that won't be the same T, and you'll need to call it with reflection, which will be somewhat painful. (Not too bad, but unpleasant.)

I suspect you don't fully understand C#/.NET generics - please give us more context about the bigger picture so we can help you better.

EDIT: The reflection approach would be something like this:

private static readonly ArrayMethod = typeof(NameOfContainingType)
    .GetMethod("GenericArrayFunction", BindingFlags.Static | BindingFlags.NonPublic);

...

static T GenericFunction<T>(T t)
{
       if (t == null) return default(T);

       if (t is Array)
       {
           Type elementType = t.GetType().GetElementType();
           MethodInfo method = ArrayMethod.MakeGenericMethod(new[] elementType);
           return (T) method.Invoke(null, new object[] { t });
       }
       ...
}

Note that this will still fail for rectangular arrays, which get even harder to cope with.

Jon Skeet
I am trying to pass T to the GenericArrayFunction. Can you please explain how to call it with reflection?
Shiftbit
I'd like to be able to pass arguments at runtime. If the argument is an array I would like to conduct Array operations, otherwise conduct the default operation.
Shiftbit
@Shiftbit: You need to give more information than that in terms of what you're really trying to do.
Jon Skeet
Thank you Jon Skeet. This is the solution I was looking for. I am using the Activator.CreateInstance Method. However, this method will not work on an array so I need to use Array.CreateInstance and therefore would like to handle it in a different method. These methods are intended to be dynamic. This is a great answer. I just need to handle the array rank.
Shiftbit
+2  A: 

It is not possible. T can never be T[]. T is always certain type, not just placeholder. If T is array (int[]) then T[] will be int[][].

Edit: There are some exceptions (like object is object[]), but in general case (and thats what generics are) T can't be T[]

Andrey
`object[]` is an `object`. So you could call `GenericFunction<object>(new object[5])`. But yes, it's unlikely.
Jon Skeet
@Jon Skeet i understood it when saw your answer :) but in general case (and thats what generics are) T can't be T[]
Andrey
On a related note, it would be possible for `T` to provide an implicit conversion operator to `T[]`, although this cannot be expressed with a generic constraint. However, it would be possible to write `class Foo : IEnumerable<Foo>` and express `where T : IEnumerable<T>` in separate constraint that would then accept `Foo`.
Ani
@Andrey: In the *general* case `T` isn't an array at all. That's not the same as saying "It is not possible." But the condition could be changed to `if (T is T[])` potentially...
Jon Skeet
+4  A: 

Judging from your particular example, could you not define two methods and let the compiler choose the correct one when an array is passed in?

using System;

class Program
{
    static T GenericFunction<T>(T t)
    {
        Console.WriteLine("GenericFunction<T>(T)");
        return default(T);
    }

    static T[] GenericFunction<T>(T[] t)
    {
        // Call the non-array function
        for(int i = 0; i < t.Length; ++i)
            t[i] = GenericFunction(t[i]);

        Console.WriteLine("GenericFunction<T>(T[])");
        return new T[4];
    }

    static void Main()
    {
        int[] arr = {1,2,3};
        int i = 42;

        GenericFunction(i);   // Calls non-array version
        GenericFunction(arr); // Calls array version
    }
}
Turnor
Unless the OP is not explaining some hidden complexity...this would be just dandy.
Rusty
+1 Very Simple solution.
Shiftbit
The problem with this is if I pass in int[] i = {...}, object o = i. GenericFunction(o). It will not go to the proper array function.
Shiftbit
@Shiftbit ..well if you want to go nuts... int[] i = {...}; object o = i; GenericFunction(**(dynamic)** o)...works. Of course getting involved with **dynamic** is a whole different kettle of scapegoats.
Rusty