3

It'd be really good if I could get an object to array conversion working.

Steps:

  1. We get passed an array from an external source. The array is boxed in an object. Typically the object is an int[] or a double[], but we normally want double[].
  2. Convert it to an array of Type T.
  3. return the converted type.

For starters, this works fine

double[] r=Array.ConvertAll<int,double>((int[])o,Convert.ToDouble)

but this doesn't (assume that T is "double") e.g. double[] R=getValue(o);

public T[] getValue<T>(object o){
// ... some logic...
return (T[])Array.ConvertAll<int,double>((int[])o,Convert.ToDouble)

Is there a where constraint that can be used? Array is a "Special Object", so we can't use that as a constraint.

Is this possible in .net without resorting to IL? Is it possilbe if we do resort to IL?

thanks, -Steven

1
  • What do you mean "resort to IL"? Are you intending to write custom IL code to workaround this? Commented Mar 30, 2011 at 10:17

5 Answers 5

3

This worked for me:

public T[] GetValue<T>(object o)
{
        Converter<int, T> c = new Converter<int, T>(input => (T)System.Convert.ChangeType(input, typeof(T)));
        return (T[])Array.ConvertAll<int, T>((int[])o, c);
}

I hope this helps!

Sign up to request clarification or add additional context in comments.

Comments

2

Try this:

public T[] getValue<T>(object o)
{
    return (T[])Convert.ChangeType(o, typeof(T[]));
}

Use like this:

object doubleArr = new Double[] {1.3, 1.5, 1.7};
var returnedValue = getValue<double>(doubleArr);

Note that if you pass in the wrong type for the template, it will fail at run time

Comments

0

-- Deleted previous content

Sorry, I did not see the Convert.ToDouble which will of course not compile. To be able to handle any type of T you have to pass a convert callback to getValue.

Something like this should do the job:

public T[] getValue<T>(object o, Converter<int, T> converter)
{
    // ... some logic...
    return (T[])Array.ConvertAll<int,T>((int[])o, converter)
}

Usage:

double[] result = getValue<double>(o, (i) => Convert.ToDouble(i));

3 Comments

Won't work either, the function won't compile. The problem is because T can be anything, and not everything can convert from double[]
@Rob: whilst it's true that not everything can be converted to a double, the Convert class does provide an overload that takes an int, so the above code would compile. (There is also an overload that takes object so it would be possible to modify the generic function to take object rather than int -- this would add the possibility of runtime errors on conversion in the example usage.)
Sorry, I should have mentioned that.
0

well all three of the above answers work. Awesome. Thanks very much.

A question: in the notation above Convert.ToDouble in the caller became (i) => Convert.ToDouble(i). Is the notation equivilent?

I'm new around here... am I supposed to accept an answer somehow? Not sure if I can because when I posted the question I wasn't registered.

In an extension to the above answers, I got this to work which is very neat solution:

public T[,,] getValue_3d<T>(object o) {
    return (T[,,])Convert.ChangeType(o,typeof(T[,,]));
}

usage:

object doubleArr=new Double[,,] { { { 1, 2, 3 }, { 4, 5, 6 } }, 
                                  { { 7, 8, 9 }, { 10, 11, 12 } } };
double[,,] returnedValue=getValue_3d<double>(doubleArr);

One of the things I tried originally was to have T (where T is an n-rank array), get the element type, and then do the conversion. It didn't work too well when it came to returning the value from the function.

To do this even more neatly, it'd be nice if we could do overloads with function return values... but to the best of my knowledge this isn't possible in C# by design. Perhaps there's a another trick. Also tried TIn + TOut to no avail (TIn is double, and TOut is double[] / double[,] / double[,,].

Thanks again.

Comments

0

Here's yet another solution :D

public T[] getValue<T>(object o) => o as T[];

However, this might return a null value because of how as works (instead of crashing --- which might be a good thing?). as works at runtime, so be careful with how you use it, but if you're using objects then you're already navigating dangerous waters.

I like doing the following so that I don't have to deal with nulls everywhere.

public T[] getValue<T>(object o) => o as T[] ?? Array.Empty<T>();

Also, this way you don't have to use another level of indirection :3


EDIT: I also noticed that you said that

Typically the object is an int[] or a double[], but we normally want double[].

if you know that you only want those two types then you could also be more explicit:

public T[] getValue<T>(object o) => o switch {
    int[] array    => array as T[],
    double[] array => array as T[],
    var _          => null,
} ?? Array.Empty<T>();

Maybe it's more of a pain to maintain, but it's a bit more explicit. Instead of returning null maybe you could throw and error also to make sure you're not passing the wrong type.

I hope this helps someone :3

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.