2012-01-16 1 views
2

入力から、weight0,weight1 ... weight49という二重変数のグループを取得します。C#:動的に変数を構成する

簡単に操作できるように、doubleアレイに動的に挿入したいと考えています。 しかし、それぞれを以下のように呼び出すのではなく、Weights[0] = weight0 ... Weights[49] = weight49私は単一のループでそれをやりたいです。

これを行う方法はありますか?基本的に

+2

なぜ配列インデックス自体を使用しないのですか、そんなに多くの変数が必要なのはなぜですか? – V4Vendetta

答えて

4

いいえ、 - あなたは配列を作成し、同時に意味しない限り:

var weights = new[] {weight0, weight1, weight2, ... , weight48, weight49}; 

個人的に、私は 50個の変数を取り除くに誘惑、そしてから配列を使用することだろうしかし、それはすべての場合に可能ではないかもしれません。

+0

残念ながら、私はシステムの制約として入力を得ることはできません。 – Freewind

1

あなたは変数名から配列のインデックスを決定するためにリフレクションを使うことができますが、効率的ではありません。詳細はpostを参照してください。

+0

ローカルメソッド変数にリフレクションでアクセスすることはできません。フィールドにしかアクセスできません。 OPがフィールドまたはメソッド変数を意味するかどうかはここでは不明です。 –

+0

それは良い点だ、私はOPがフィールドを参照していると仮定していた、私はそれがまだ有用であると思うように私の答えを削除するために投票しません。 –

0

私は、これはあなたにすべてのオプションを与える、あなたは配列のために必要かもしれないと思うKeyValuePair- Listobject

// sample data 
    var weight = 1.00; 

    // create a list 
    var tmp = new List<KeyValuePair<string,object>>(); 

    // Here you can add your variables 
    tmp.Add(new KeyValuePair<string,object>("weights" + tmp.Count.ToString() 
      , weight)); 

    // If needed convert to array 
    var weights = tmp.ToArray(); 

    // get the information out of the array 
    var weightValue = weights[0].Value; 
    var weightKey = weights[0].Key; 

でそれを行うにしようとするだろう。試してみる。

0

私はこれを入れているあなたはそれを行うことができますので、 - 限り、これらの変数は、実際にフィールド/プロパティあるとして。 であるべきかどうかは、このソリューションは再利用可能ですが、遅いです(デリゲートキャッシングが必要です)。私はMarc Gravellに同意する必要があります。

変数がプロパティの場合は変更する必要があります。また、(このソリューションはすべての倍精度のコピーを持つ配列を生成するため、私はボックス型の倍精度浮動小数点型(double型)のオブジェクト配列を作成することは考えていません)、別の方法が必要です。

だからここに行く。コード/拡張メソッドの聖なる壁:

//paste this as a direct child of a namespace (not a nested class) 
public static class SO8877853Extensions 
{ 
    public static TArray[] FieldsToArray<TObj, TArray>(this TObj o,string fieldPrefix) 
    { 
    if(string.IsNullOrWhiteSpace(fieldPrefix)) 
     throw new ArgumentException("fieldPrefix must not null/empty/whitespace", 
     "fieldPrefix"); 

    //I've done this slightly more expanded than it really needs to be... 
    var fields = typeof(TObj).GetFields(System.Reflection.BindingFlags.Instance 
      | System.Reflection.BindingFlags.Public 
      | System.Reflection.BindingFlags.NonPublic) 
    .Where(f =>f.Name.StartsWith(fieldPrefix) && f.FieldType.Equals(typeof(TArray))) 
    .Select(f =>new{ Field = f, OrdinalStr = f.Name.Substring(fieldPrefix.Length)}) 
    .Where(f => { int unused; return int.TryParse(f.OrdinalStr, out unused);}) 
    .Select(f => new { Field = f.Field, Ordinal = int.Parse(f.OrdinalStr) }) 
    .OrderBy(f => f.Ordinal).ToArray(); 
    //doesn't handle ordinal gaps e.g. 0,1,2,7 

    if(fields.Length == 0) 
     throw new ArgumentException(
     string.Format("No fields found with the prefix {0}", 
         fieldPrefix), 
     "fieldPrefix"); 

    //could instead bake the 'o' reference as a constant - but if 
    //you are caching the delegate, it makes it non-reusable. 
    ParameterExpression pThis = Expression.Parameter(o.GetType()); 

    //generates a dynamic new double[] { var0, var1 ... } expression 
    var lambda = Expression.Lambda<Func<TObj, TArray[]>>(
     Expression.NewArrayInit(typeof(TArray), 
     fields.Select(f => Expression.Field(pThis, f.Field))), pThis); 
    //you could cache this delegate here by typeof(TObj), 
    //fieldPrefix and typeof(TArray) in a Dictionary/ConcurrentDictionary 
    return lambda.Compile()(o); 
    } 
} 

上記の拡張方法はどのタイプでも機能します。コードでラムダの作成を簡略化するために、インスタンス型と目的の配列型の両方に汎用的です。にはが含まれていません。

フィールドグループの名前プレフィックス(ケース"weight")を渡すと、そのプレフィックスを持つもののすべてのパブリックフィールドとプライベートインスタンスフィールドが検索され、そのフィールドは接尾辞が整数に解析されます。その後、その序数に基づいてこれらのフィールドを注文します。序数リストの隙間をチェックするわけではないので、weight0weight2の型は動作しますが、2要素の配列しか作成しません。

次に、式ツリーを使用して動的なコードをベイクしてコンパイルします(この時点でコードに記載されているとおり、後で使用するためにデリゲートをTObjTArrayにキャッシュするとよいでしょう)結果を返します。私はこれをやって容認いないよ、でも私はそれのために任意の+1を期待しています - - しかし、私は私が言うのと同じように

private class SO8877853 
{ 
    private double field0 = 1.0; 
    private double field1 = -5.0; 
    private double field2 = 10.0; 
    public double[] AsArray() 
    { 
     //it would be nice not to have to pass both type names here - that 
     //can be achieved by making the extension method pass out the array 
     //via an 'out TArray[]' instead. 
     return this.FieldsToArray<SO8877853, double>("field"); 
    } 
} 

[TestMethod] 
public void TestThatItWorks() 
{ 
    var asArray = new SO8877853().AsArray(); 
    Assert.IsTrue(new[] { 1.0, -5.0, 10.0 }.SequenceEqual(asArray)); 
} 

今標準ユニットテストプロジェクトでテストクラスにこれを追加挑戦のための吸盤:)

関連する問題