0

次のクラスとデータがあるとします。

public class InnerExample
{
    public string Inner1 { get; set; }
}


public class Example
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public List<InnerExample> Inner { get; set; }
}

var a = new Example
{
    Property1 = "Foo",
    Property2 = "Bar",
    Inner = new List<InnerExample>
    {
      new InnerExample
      {
        Inner1 = "This is the value to change"
      }
   }
};

パスで最も内側のデータにアクセスする方法はありますか?

何か言い方はありますか...

a["Inner[0].Inner1"] = "New value"

この特定のケースでは、存在しないキーにアクセスすることは決してないという事実を知っているので、エラー チェックについて過度に心配する必要はありません。

(これが以前に尋ねられた場合は申し訳ありません。いくつかの検索を行いましたが、試すキーワードがすぐになくなりました。)

4

2 に答える 2

0

ジョン、あなたが私にくれた基本的なアドバイスのおかげで、私の場合に有効な解決策を思いつきました.

  • エラーチェックはありません
  • 配列要素ではなく、プロパティを設定する必要があります。
  • これを行うためのより効率的な方法があると確信しています...私はリフレクションの専門家にはほど遠いです。

    /// <summary>
    /// Take an extended key and walk through an object to update it.
    /// </summary>
    /// <param name="o">The object to update</param>
    /// <param name="key">The key in the form of "NestedThing.List[2].key"</param>
    /// <param name="value">The value to update to</param>
    private static void UpdateModel(object o, string key, object value)
    {
        // TODO:
        // Make the code more efficient.
    
        var target = o;
        PropertyInfo pi = null;
    
        // Split the key into bits.
        var steps = key.Split('.').ToList();
    
        // Don't walk all the way to the end
        // Save that for the last step.
        var lastStep = steps[steps.Count-1];
        steps.RemoveAt(steps.Count-1);
    
        // Step through the bits.
        foreach (var bit in steps)
        {
            var step = bit;
    
            string index = null;
    
            // Is this an indexed property?
            if (step.EndsWith("]"))
            {
                // Extract out the value of the index
                var end = step.IndexOf("[", System.StringComparison.Ordinal);
                index = step.Substring(end+1, step.Length - end - 2);
    
                // and trim 'step' back down to exclude it.  (List[5] becomes List)
                step = step.Substring(0, end);
            }
    
            // Get the new target.
            pi = target.GetType().GetProperty(step);
            target = pi.GetValue(target);
    
            // If the target had an index, find it now.
            if (index != null)
            {
                var idx = Convert.ToInt16(index);
    
                // The most generic way to handle it.
                var list = (IEnumerable) target;
                foreach (var e in list)
                {
                    if (idx ==0)
                    {
                        target = e;
                        break;
                    }
                    idx--;
                }
            }
        }
    
        // Now at the end we can apply the last step,
        // actually setting the new value.
        if (pi != null || steps.Count == 0)
        {
            pi = target.GetType().GetProperty(lastStep);
            pi.SetValue(target, value);
        }
    }
    
于 2013-10-30T17:14:00.717 に答える
0

組み込みのものは何もありませんが、それを行うことは可能です (たとえ些細なことではありませんが)。

必要なのは、クラスにインデクサーを追加することですExample。インデクサー内では、提供された「プロパティ パス」をステップに解析し、リフレクションを使用してターゲット プロパティをステップごとに解決する必要があります。

たとえば、Inner[0].Inner13 つの異なるステップ ( fetch Inner、次に from that fetch [0]、次に from that Inner1) に解析した後、ループは次のようになります。

// This works only with plain (non-indexed) properties, no error checking, etc.
object target = this;
PropertyInfo pi = null;
foreach (var step in steps)
{
    pi = target.GetType().GetProperty(step);
    target = pi.GetValue(target);
}

// And now you can either return target (on a get) or use pi.SetValue (on a set)
于 2013-10-30T10:00:21.687 に答える