简体   繁体   中英

C# Convert object of type array to T, where T is an array?

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") eg 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

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!

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

-- 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));

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.

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 object s then you're already navigating dangerous waters.

I like doing the following so that I don't have to deal with null s 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM