Atomically Copying One Array to Another Array

If we’re copying arrays where the types may be different, sometimes we may want to do an atomic copy; that is if any of the elements in the source array can’t be converted to the destination array type, the whole copy operation will “rollback” and the target array will remain unchanged.

The Array.ConstrainedCopy method can do this for us.

Consider the code below where an array of objects (containing a string and and an int) is copied to a target array of type string.

Using .CopyTo will result in an exception and the target array being partially affected (the target array element 0 will have already been populated with the string).

Using .ConstrainedCopy will ensure that if an exception occurs the target array will be “rolled back”, i.e. none of it’s elements will have been changed.

var things = new object[] { "Sarah", 1};

var strings = new string[2];


// this will throw an exception because of the 2nd element conversion error (int to string)
// but, the target array "strings" would have been changed (the 1st string element will have been copied)
things.CopyTo(strings, 0);


// this will throw an exception because of the 2nd element conversion error (int to string)
// BUT, the target array "strings" will NOT have been changed
Array.ConstrainedCopy(things, 0, strings, 0, 2);

The constrained copy has the following parameters (from MSDN):

public static void ConstrainedCopy(
    Array sourceArray,
    int sourceIndex,
    Array destinationArray,
    int destinationIndex,
    int length
)

 

For more C# tips, feel free to check out my C# Tips and Traps Pluralsight course.

Comments (1) -

  • Cameron MacFarland

    8/26/2013 11:22:51 AM | Reply

    You got me all excited for a moment, but ConstrainedCopy is not atomic, just transactional. The following code shows this.

        int count = 10;
        var things = Enumerable.Range(0, count).Select(i => i.ToString()).ToArray();
        var strings = new string[count];
        var task = Task.Run(() => { Array.ConstrainedCopy(things, 0, strings, 0, count); });
        var task2 = Task.Run(() => { things[count-1] = "foo"; });
        Task.WaitAll(task, task2);
        strings[count-1].Dump();

    Changing the count from 10 to 100 or higher will change the result of the output at the end. This is because the second task is changing the last value before the ConstrainedCopy is completed.

Pingbacks and trackbacks (1)+

Add comment

Loading