web-dev-qa-db-ja.com

C#で配列の長さを動的に設定する方法

私はまだ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などを使用できません)。

追伸「コメントの追加」機能を使用して、投稿された質問をフォローアップする唯一の方法はありますか?

21
John Adams

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

コードは少なくなりますが、同じ量の作業(つまり、新しい配列の作成と古いアイテムのコピー)を行うことになります。

20
Jim Mischel
InputProperty[] ip = new InputProperty[nvPairs.Length]; 

または、次のようなリストを使用できます。

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

もう1つ指摘したいのは、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;
}
28
BFree

配列である必要がありますか? ArrayListまたはC#で利用可能な他のオブジェクトのいずれかを使用する場合、コンテンツに対するこの制限はありません。ハッシュテーブル、IDictionnary、IListなどはすべて、要素の動的な数を許可します。

5
Brian

これを使って:

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

メソッド内で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;
    }
2
Michael Piendl

または、System.Linqを使用するC#3.0では、中間リストをスキップできます。

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

つかいます 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;
    }
1
Johannes

この方法で動的に配列を作成できます。

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

    }
0
lukaszk

通常、配列はサイズを初期化するために定数を必要とします。 nvPairsを1回スイープして長さを取得し、次にこのような長さの変数を使用して「動的に」配列を作成できます。

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

ただし、お勧めしません。だけに固執する

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

溶液。パフォーマンスはそれほど劣らず、見た目も良くありません。

0
Michael Meadows