Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I have a solution that works with your example data. It is not a universal solution and may fail with other examples, but it shows how to use recursions. I did not include any error handling. A real-world solution would have to.</p> <p>I use this helper method which gets the item type of the generic lists:</p> <pre><code>private static Type GetListItemType(Type listType) { Type itemType = null; foreach (Type interfaceType in listType.GetInterfaces()) { if (interfaceType.IsGenericType &amp;&amp; interfaceType.GetGenericTypeDefinition() == typeof(IList&lt;&gt;)) { itemType = interfaceType.GetGenericArguments()[0]; break; } } return itemType; } </code></pre> <p>Now, the recursion:</p> <pre><code>public void SplitKeyValues(IList source, List&lt;object&gt; keys, List&lt;object&gt; values) { Type itemType = GetListItemType(source.GetType()); PropertyInfo[] properties = itemType.GetProperties(); for (int i = 0; i &lt; source.Count; i++) { object item = source[i]; var itemValues = new List&lt;object&gt;(); values.Add(itemValues); foreach (PropertyInfo prop in properties) { if (typeof(IList).IsAssignableFrom(prop.PropertyType) &amp;&amp; prop.PropertyType.IsGenericType) { // We have a List&lt;T&gt; or array Type genericArgType = GetListItemType(prop.PropertyType); if (genericArgType.IsValueType || genericArgType == typeof(string)) { // We have a list or array of a simple type if (i == 0) keys.Add(prop.Name); List&lt;object&gt; subValues = new List&lt;object&gt;(); itemValues.Add(subValues); subValues.AddRange( Enumerable.Cast&lt;object&gt;( (IEnumerable)prop.GetValue(item, null))); } else { // We have a list or array of a complex type List&lt;object&gt; subKeys = new List&lt;object&gt;(); if (i == 0) keys.Add(subKeys); List&lt;object&gt; subValues = new List&lt;object&gt;(); itemValues.Add(subValues); SplitKeyValues( (IList)prop.GetValue(item, null), subKeys, subValues); } } else if (prop.PropertyType.IsValueType || prop.PropertyType == typeof(string)) { // We have a simple type if (i == 0) keys.Add(prop.Name); itemValues.Add(prop.GetValue(item, null)); } else { // We have a complex type. // Does not occur in your example } } } } </code></pre> <p>I call it like this:</p> <pre><code>List&lt;User&gt; userList = InitializeObjects(); List&lt;object&gt; keys = new List&lt;object&gt;(); List&lt;object&gt; values = new List&lt;object&gt;(); SplitKeyValues(userList, keys, values); </code></pre> <p><code>InitializeObjects</code> initializes the user list as you did above.</p> <hr> <p><strong>UPDATE</strong></p> <p>The problem is that you are using an anonymous type <code>new { Friends = ... }</code>. You would have to create an anonymous type dynamically by using reflection. And that's pretty nasty. The article <a href="http://www.developmentalmadness.com/archive/2008/02/12/extend-anonymous-types-using.aspx" rel="nofollow noreferrer">"Extend Anonymous Types using Reflection.Emit"</a> seems to do it. (I didn't test it).</p> <p>Maybe an easier approach would do the job. I suggest creating a helper class for the description of class types.</p> <pre><code>public class Class { public string Name { get; set; } public List&lt;object&gt; Structure { get; set; } } </code></pre> <p>Now let's replace an else case in the code above:</p> <pre><code>... } else { // We have a list or array of a complex type List&lt;object&gt; subKeys = new List&lt;object&gt;(); var classDescr = new Class { Name = genericArgType.Name, Structure = subKeys }; if (i == 0) keys.Add(classDescr); List&lt;object&gt; subValues = new List&lt;object&gt;(); itemValues.Add(subValues); SplitKeyValues( (IList)prop.GetValue(item, null), subKeys, subValues); } ... </code></pre> <p>The result is: <img src="https://i.stack.imgur.com/JHNZj.png" alt="enter image description here"></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload