Как установить длину массива в C# динамически

Я все еще новичок в C#, и я боролся с различными проблемами в массивах. У меня есть массив объектов метаданных (пары значений имен), и я хотел бы знать, как создать только количество объектов "InputProperty", которые мне действительно нужны. В этом цикле я произвольно установил количество элементов в 20, и я пытаюсь выручить, когда запись становится нулевой, но веб-службе на получающем конце этого не нравятся никакие нулевые элементы, переданные ему:

private Update BuildMetaData(MetaData[] nvPairs)
{
    Update update = new Update();
    InputProperty[] ip = new InputProperty[20];  // how to make this "dynamic"
    int i;
    for (i = 0; i < nvPairs.Length; i++)
    {
        if (nvPairs[i] == null) break;
        ip[i] = new InputProperty();
        ip[i].Name = "udf:" + nvPairs[i].Name;
        ip[i].Val = nvPairs[i].Value;
    }
    update.Items = ip;
    return update;
}

подводя итог, скажем У меня есть только 3 пары namevalue в приведенном выше входном массиве? Вместо того, чтобы выделять 20 элементов для массива, называемого ip, как можно кодировать это, чтобы ip был только таким большим, каким он должен быть. Объект update передается через другой веб-сервис, поэтому сериализация важна (т. е. я не могу использовать namevaluecollection и т. д.).

p.s. Является ли единственный способ следить за опубликованным вопросом через средство "добавить комментарии"?

9 ответов


если вы не хотите использовать List, ArrayList или другая коллекция динамического размера, а затем преобразовать в массив (это метод, который я бы рекомендовал, кстати), то вам придется выделить массив до его максимально возможного размера, отслеживать, сколько элементов вы положили в него, а затем создать новый массив только с этими элементами в нем:

private Update BuildMetaData(MetaData[] nvPairs)
{
    Update update = new Update();
    InputProperty[] ip = new InputProperty[20];  // how to make this "dynamic"
    int i;
    for (i = 0; i < nvPairs.Length; i++)
    {
        if (nvPairs[i] == null) break;
        ip[i] = new InputProperty(); 
        ip[i].Name = "udf:" + nvPairs[i].Name;
        ip[i].Val = nvPairs[i].Value;
    }
    if (i < nvPairs.Length)
    {
        // Create new, smaller, array to hold the items we processed.
        update.Items = new InputProperty[i];
        Array.Copy(ip, update.Items, i);
    }
    else
    {
        update.Items = ip;
    }
    return update;
}

альтернативным методом было бы всегда назначать update.Items = ip; а затем при необходимости изменить размер:

update.Items = ip;
if (i < nvPairs.Length)
{
    Array.Resize(update.Items, i);
}

меньше кода, но, скорее всего, будет делать тот же объем работы (т. е. создает новый массив и копировать старые элементы).


InputProperty[] ip = new InputProperty[nvPairs.Length]; 

или вы можете использовать такой список:

List<InputProperty> list = new List<InputProperty>();
InputProperty ip = new (..);
list.Add(ip);
update.items = list.ToArray();

еще одна вещь, которую я хотел бы отметить, в C# вы можете использовать переменную int в цикле for прямо внутри цикла:

for(int i = 0; i<nvPairs.Length;i++
{
.
.
}

и только потому, что я в настроении, вот более чистый способ сделать этот метод IMO:

private Update BuildMetaData(MetaData[] nvPairs)
{
        Update update = new Update();
        var ip = new List<InputProperty>();

        foreach(var nvPair in nvPairs)
        {
            if (nvPair == null) break;
            var inputProp = new InputProperty
            {
               Name = "udf:" + nvPair.Name,
               Val = nvPair.Value
            };
            ip.Add(inputProp);
        }
        update.Items = ip.ToArray();
        return update;
}

должен ли is быть массивом? Если вы используете ArrayList или один из других объектов, доступных в C#, у вас не будет этого ограничения для содержимого. Hashtable, IDictionnary, IList и т. д.. все позволяют динамическое количество элементов.


используйте этот:

 Array.Resize(ref myArr, myArr.Length + 5);

вы можете использовать List внутри метода и преобразовать его в массив в конце. Но я думаю, что если мы говорим о максимальном значении 20, ваш код быстрее.

    private Update BuildMetaData(MetaData[] nvPairs)
    {
        Update update = new Update();
        List<InputProperty> ip = new List<InputProperty>();
        for (int i = 0; i < nvPairs.Length; i++)
        {
            if (nvPairs[i] == null) break;
            ip[i] = new InputProperty();
            ip[i].Name = "udf:" + nvPairs[i].Name;
            ip[i].Val = nvPairs[i].Value;
        }
        update.Items = ip.ToArray();
        return update;
    }

или в C# 3.0 с использованием System.Linq вы можете пропустить промежуточный список:

private Update BuildMetaData(MetaData[] nvPairs)
{
        Update update = new Update();
        var ip = from nv in nvPairs
                 select new InputProperty()
                 {
                     Name = "udf:" + nv.Name,
                     Val = nv.Value
                 };
        update.Items = ip.ToArray();
        return update;
}

использовать Array.CreateInstance для динамического создания массива.

    private Update BuildMetaData(MetaData[] nvPairs)
    {
        Update update = new Update();
        InputProperty[] ip = Array.CreateInstance(typeof(InputProperty), nvPairs.Count()) as InputProperty[];
        int i;
        for (i = 0; i < nvPairs.Length; i++)
        {
            if (nvPairs[i] == null) break;
            ip[i] = new InputProperty();
            ip[i].Name = "udf:" + nvPairs[i].Name;
            ip[i].Val = nvPairs[i].Value;
        }
        update.Items = ip;
        return update;
    }

как правило, массивы требуют констант для инициализации их размера. Вы можете пройтись по nvPairs один раз, чтобы получить длину, а затем "динамически" создать массив, используя переменную для длины.

InputProperty[] ip = (InputProperty[])Array.CreateInstance(typeof(InputProperty), length);

Я бы не рекомендовал это, хотя. Просто придерживайтесь

List<InputProperty> ip = ...
...
update.Items = ip.ToArray();

решение. Это не намного менее эффективно, и намного лучше выглядит.


вы можете создать массив динамически таким образом:

 static void Main()
    {
        // Create a string array 2 elements in length:
        int arrayLength = 2;
        Array dynamicArray = Array.CreateInstance(typeof(int), arrayLength);
        dynamicArray.SetValue(234, 0);                              //  → a[0] = 234;
        dynamicArray.SetValue(444, 1);                              //  → a[1] = 444;
        int number = (int)dynamicArray.GetValue(0);                      //  → number = a[0];


        int[] cSharpArray = (int[])dynamicArray;
        int s2 = cSharpArray[0];

    }