Pregunta

If I have a simple Utility function that copies an array to a new array:

public static object[] CopyTo(object[] original, int startIndex, int endIndex)
{
    List<object> copied - new List<object>();
    for (int i = startIndex; i <= endIndex; i++) 
    {
        copied.Add(original[i]);
    }
    return copied.ToArray();
}

and I want to then be able to call it like this:

int[] newThing = CopyTo(new int[] { 10, 9, 8, 7, 6 }, 2, 4);

the compiler errors saying cannot convert from int[] to object[]. This is expected since my CopyTo function specifically wants an object array, not an integer array.

How can I change the declaration of CopyTo in order for it to dynamically accept and return an array of any type? I believe Generics is the way (though I'm not too familiar with this) so I tried:

public static T[] CopyTo(T[] original, int startIndex......)

but the compiler won't recognise T as a type.

¿Fue útil?

Solución

To make it generic use following code:

public static T[] CopyTo<T>(T[] original, int startIndex, int endIndex)
{
    List<T> copied = new List<T>();
    for (int i = startIndex; i <= endIndex; i++) 
    {
        copied.Add(original[i]);
    }
    return copied.ToArray();
}

Edit:

Just to mention, you can also do this without creating a List<T> and returning the list as an array. Just create an array (with length equal to the count of wanted elements) and fill it up:

public static T[] CopyTo<T>(T[] original, int startIndex, int endIndex)
{
    int count = (endIndex - startIndex) + 1;
    int index = 0;
    T[] copied = new T[count];

    for (int i = startIndex; i <= endIndex; i++) 
        copied[index++] = original[i];

    return copied;
}

And you could also create an extension method for it:

public static class Extensions
{
    public static T[] CopyTo<T>(this T[] source, int start, int end)
    {
        int count = (end - start) + 1;
        int index = 0;
        T[] copied = new T[count];

        for (int i = start; i <= end; i++) 
            copied[index++] = source[i];

        return copied;
    }
}

Now you can call it like:

var original = new int[] { 10, 9, 8, 7, 6 };
var newThing = original.CopyTo(0, 2);

Or for an array of strings:

var strOrig = "one.two.three.four.five.six.seven".Split('.');
var strNew = strOrig.CopyTo(2, 5);

Otros consejos

You don't need to write your own function, the .NET Framework has already everything built in. You have two options:

  • Array.Copy(sourceArray, srcStartIndex, targetArray, tgtStartIndex, srcNumberOfElements);
  • sourceArray.CopyTo(targetArray, tgtStartIndex);

I will first explain them with some examples, and at the end I will put it together to a function

public static T[] CopyFromArray<T>(this T[] sourceArray, int startIndex, int endIndex)

as you requested it in your question (CopyTo is already reserved by .NET so I renamed it to CopyFromArray).

Note that sourceArray and targetArray are arrays of any type; srcStartIndex is the start index of the sourceArray to copy from, tgtStartIndex is the start index of the targetArray to copy to, and srcNumberOfElements is the number of elements you want to copy from the source array.

The target array must be big enough to copy all elements into, otherwise you will get an error. The elements of the source array are directly copied into the target array ("in situ"), which is why there isn't any data returned from the functions (return type is void).

Look at this example:

void Main()
{
    var target = new int[20];
    var srcStart=1; var tgtStart=3; var srcElements=3;
    Array.Copy((new int[] { 1,2,3,4,5,6,7,8,9 }), srcStart, 
        target, tgtStart, srcElements);
    Console.WriteLine(string.Join(",", target));
}

It works correctly and returns:

0,0,0,2,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0

Note that srcStart specifies the index in the source array, from which it starts to copy, while tgtStart specifies the index in the target array where it starts to insert, and finally, srcElements specifies how many elements there are to be copied.


Note there is also a simpler version, the .CopyTo method. It works as follows:

void Main()
{
    var target = new int[20]; var tgtStart = 3;
    (new int[] { 1,2,3,4,5,6,7,8,9 }).CopyTo(target, tgtStart);
    Console.WriteLine(string.Join(",", target));
}

And it returns:

0,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,0

The 2nd parameter specifies the index at which position the data shall be inserted (just like tgtStart in the previous example), this is why the first 3 elements are 0.

You can use it with other data types too, for example:

    var target = new string[20];
    (new string[] { "abc", "def", "ghi" }).CopyTo(target, 3);

works in the same way.


Coming to your question, you can use the information I gave you so far to put together your own generic extension method like this:

void Main()
{
    int[] newThing1 = (new int[] { 10, 9, 8, 7, 6 }).CopyFromArray(2, 4);
    newThing1.Dump();

    string[] newThing2 = (new string[] { "A",  "B",  "C",  "D"}).CopyFromArray(1, 3);
    newThing2.Dump();
}

public static class Extensions
{
    public static T[] CopyFromArray<T>(this T[] sourceArray, int startIndex, int endIndex)
    {
        int numberOfElements = endIndex - startIndex + 1;
        var targetArray = new T[numberOfElements];
        Array.Copy(sourceArray, startIndex, targetArray, 0, numberOfElements);
        return targetArray;
    }
}

Try this:

public static T[] CopyTo<T>(T[] original, int startIndex, int endIndex)
{
    List<T> copied = new List<T>();
    for (int i = startIndex; i < endIndex; i++) 
    {
        copied.Add(original[i]);
    }
    return copied.ToArray();
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top