1

I was wondering if it's possible to use some sort of Array.Copy method in C# to copy elements of one array to and array of same size but different type. I get a struct from a native c++ library that contains a pointer to Integer and a size element. These integer values represent enum Values from enum Foo. At the moment I'm using a for loop. Is there a better/safer approach? Thanks!

Using Array.Copy throws an ArrayTypeMismatchException as shown below:

using System;

public class Program
{
    public enum Foo
    {
        FOO_1,
        FOO_2
    }

    public static void Main(string[] args)
    {
        int nCount = 1;
        Foo[] fooArr = new Foo[nCount];
        Int32[] RawData = new Int32[nCount];
        RawData[0] = 100;
        Array.Copy(RawData, fooArr, nCount);
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
tzippy
  • 6,458
  • 30
  • 82
  • 151
  • 2
    Well you can call `Array.Copy(RawData, 0, fooArr, 0, RawData.Length`) already... Given that you already know about `Array.Copy`, did you try it and find some problem? The native C++ part seems irrelevant to me - if you're just trying to copy from an `int[]` to a `Foo[]` where `Foo` is an enum with an underlying type of `int`, that's fine... if you have problems, please provide a [mcve]. – Jon Skeet Jul 27 '17 at 07:43
  • Your question _"Is there a better/safer approach?"_ is unclear. What kind of answers are you looking for _exactly_? What's not working about this approach? – CodeCaster Jul 27 '17 at 07:48
  • I edited the question with an answer to the question why I dont use Array.Copy – tzippy Jul 27 '17 at 07:51
  • It won't with the types you've given. I've just tried it. Please, please provide a [mcve]. – Jon Skeet Jul 27 '17 at 07:55
  • Example: http://rextester.com/LNXY25400 – tzippy Jul 27 '17 at 08:04
  • Please put it *in the question* (not as a link). – Jon Skeet Jul 27 '17 at 08:12
  • (But that's certainly surprising, as I tried the same thing locally before my first comment. Will have to investigate a bit more. Currently at breakfast...) – Jon Skeet Jul 27 '17 at 08:14
  • Ah.. I think I know what I did wrong. For some reason it's fine to copy from the enum array to the int array, but not vice versa. That's very strange. I probably did it the wrong way round in my test app. – Jon Skeet Jul 27 '17 at 08:16
  • There's another option that might work without copying at all, depending on what you need to do with the array afterwards. Will need to check though... – Jon Skeet Jul 27 '17 at 08:17
  • As I said before, please *don't* just put a link in the question. Include the code in the question itself - I've edited the question for you now, but *please* do this yourself in future. It makes for a much, much better question. – Jon Skeet Jul 27 '17 at 08:35
  • I did put the code in the question actually. Now the code is there twice. – tzippy Jul 27 '17 at 08:36
  • I've edited it - sorry, I hadn't realized you'd got rid of the current *working* code as well (I skimmed over your repro code, thinking it was the original code), given that you'd ended with "edit 2" and the link... I've left just the trimmed version - there's no need to have the namespace declaration, or the useless whitespace, or the using directives for namespaces you're not using. – Jon Skeet Jul 27 '17 at 08:39

2 Answers2

7

You could do it with LINQ:

fooArr = RawData.Select(r => (Foo)r).ToArray();
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
Romano Zumbé
  • 7,893
  • 4
  • 33
  • 55
  • 3
    There's no need to do that here. The OP just wants to copy one array to another, and `Array.Copy` does that fine. – Jon Skeet Jul 27 '17 at 07:44
  • 1
    @JonSkeet In this specific case, thats right. But I wanted to answer the question in a more general way, where an implicit conversion (int => enum) wouldn't be possible. That fits the questions title better – Romano Zumbé Jul 27 '17 at 07:45
  • 1
    If you believe that to be the question, vote to close as a duplicate of [C# Cast Entire Array?](https://stackoverflow.com/questions/2068120/c-sharp-cast-entire-array) instead. But it isn't. – CodeCaster Jul 27 '17 at 07:46
  • But the question really does seem pretty specific - so why not answer that specific question? – Jon Skeet Jul 27 '17 at 07:46
  • Note that it's not the presence of an implicit conversion that's important here - it's that it's a conversion that the CLR is fine with, so `Array.Copy` works. (This *wouldn't* be true copying an `int[]` to a `double[]` for example.) – Jon Skeet Jul 27 '17 at 07:47
  • @JonSkeet Actually, I edited the question with what `Array.Copy` results in – tzippy Jul 27 '17 at 07:52
4

For some reason, neither Array.Copy nor Buffer.BlockCopy is happy to copy from an int[] to a Foo[], although Array.Copy can go in the other direction perfectly happily.

It looks to me like your options are:

  • The kind of copy you showed in your original post, although I'd write it as:

    for (int i = 0; i < RawData.Length; i++)
    {
        fooArr[i] = RawData[i];
    }
    

    .. that way you don't have a redundant variable outside the scope of the loop

  • A LINQ-based approach as suggested by Romano Zumbé, although in that case you shouldn't create the array beforehand as well
  • A LINQ-like-but-not-LINQ approach using Array.ConvertAll:

    var fooArr = Array.ConvertAll(RawData, x => (Foo) x);
    

    ... this is more efficient than the LINQ approach as it can create an array of the correct size to start with.

  • If you don't need the execution-time type to actually be Foo[], you can just cast without any copying... because the CLR is happy to treat an int[] as a Foo[]:

    Foo[] fooArr = (Foo[]) (object) RawData;
    

    At that point, you have a single array object, which you're viewing as either an int[] (via RawData) or a Foo[] (via fooArr). Changes via either variable will be visible in the other variable. This is clearly very efficient, but could lead to problems elsewhere depending on how you use fooArr. If you just use it in foreach loops or via regular index accesses, it would be fine.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194