【问题标题】:How to set array length in c# dynamically如何在c#中动态设置数组长度
【发布时间】:2010-10-15 13:08:00
【问题描述】:

我还是 C# 的新手,并且一直在努力解决有关数组的各种问题。我有一组元数据对象(名称值对),我想知道如何只创建我真正需要的数量的“InputProperty”对象。在这个循环中,我将元素的数量任意设置为 20,并尝试在条目变为 null 时退出,但接收端的 Web 服务不喜欢传递给它的任何 null 元素:

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 个名称值对?与其为名为 ip 的数组分配 20 个元素,不如编写代码使 ip 仅与需要的一样大。更新对象通过另一个 Web 服务传递,因此序列化很重要(即我不能使用 namevaluecollection 等)。

附言是通过“添加 cmets”工具跟进已发布问题的唯一方法吗?

【问题讨论】:

    标签: c# arrays object array-initialize


    【解决方案1】:

    您可以通过这种方式动态创建数组:

     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];
    
        }
    

    【讨论】:

      【解决方案2】:

      使用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;
          }
      

      【讨论】:

        【解决方案3】:

        使用这个:

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

        【讨论】:

          【解决方案4】:
          InputProperty[] ip = new InputProperty[nvPairs.Length]; 
          

          或者,您可以使用这样的列表:

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

          我想指出的另一件事是,在 C# 中,您可以在循环内部的 for 循环中删除 int 变量的使用:

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

          【讨论】:

          • 我认为您在这里遗漏了问题——输入数组 nvPairs 在有用的值之后包含空值。仅仅使用它的长度不会解决任何问题。
          • OP 从未指定过。我只是假设 if null 是一个简单的完整性检查。如果你说的是事实,那你是对的。列表肯定是要走的路。
          • 嗯,我不认为这可能是一个健全性检查。这当然是可能的。
          • Whatsit 是正确的(输入数组 nvPairs 在有用的条目之后包含空条目。我尝试了上面 BFree 提供的“更清洁”方式,稍作改动以绕过编译时错误。
          • 如果名为 ip 的数组分配了与 nvPairs 相同的长度,上面的代码如何让数组 ip 填充对象。我在 foreach 循环中看到了 InputProperty 对象的创建,但我看不到这些对象是如何添加到数组 ip 中的。
          【解决方案5】:

          通常,数组需要常量来初始化它们的大小。您可以扫描一次 nvPairs 以获得长度,然后“动态”使用这样的长度变量创建一个数组。

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

          不过,我不会推荐它。只要坚持

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

          解决方案。它的性能并没有那么差,而且看起来更好。

          【讨论】:

            【解决方案6】:

            如果您不想使用 ListArrayList 或其他动态大小的集合然后转换为数组(顺便说一下,这是我推荐的方法),那么您将必须将数组分配到其最大可能大小,跟踪您放入其中的项目数,然后创建一个仅包含这些项目的新数组:

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

            它的代码更少,但最终可能会完成相同数量的工作(即创建一个新数组并复制旧项目)。

            【讨论】:

              【解决方案7】:

              或者在 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;
              }
              

              【讨论】:

              • 你忘记检查 nv 是否为空
              【解决方案8】:

              您可以在方法中使用 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;
                  }
              

              【讨论】:

              • 上面的改编代码。获取“找不到类型或命名空间名称'List'(您是否缺少 using 指令或程序集引用?)我也有这个(他还想要什么): using System.Collections; using System.Collections.Generic ; 使用 System.Collections.Specialized;
              【解决方案9】:

              is 需要是一个数组吗?如果您使用 ArrayList 或 C# 中可用的其他对象之一,则内容不会受到此限制。 Hashtable、IDictionnary、IList 等。都允许动态数量的元素。

              【讨论】:

              • 我同意。如果您需要数组的功能并具有动态长度,那么 ArrayList 是最简单明了的答案。
              • 数组列表?我们对仿制药过敏吗?
              • michl86 cmets 最后使用 List 和 .ToArray 太慢了。看起来 ArrayList 可以以相同的方式转换为数组。对于我的最终结果,我需要一个数组而不是 ArrayList。在返回之前使用 .ToArray() 的性能有那么差吗?
              • 哈哈 - 通用也很酷。我试图让它尽可能接近他使用的东西。
              • 我必须将此对象传递给的 Web 服务需要一个 InputProperty 对象数组,其中没有空条目。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-10-10
              • 1970-01-01
              • 1970-01-01
              • 2019-10-28
              • 1970-01-01
              • 2019-05-12
              • 2020-11-11
              相关资源
              最近更新 更多