-1

I am using VS2010 and EF4.0. The goal is to select fields of any IEnumerable, in order to show in the DataGridView. Take Northwind.Employees as example, the following code is OK.

private void button1_Click(object sender, EventArgs e)
{
    NorthwindEntities en = new NorthwindEntities();
    dataGridView1.DataSource = SelectNew(en.Employees, new string[] { "EmployeeID", "FirstName" });
}

public object SelectNew(object items, string[] fields)
{
    IEnumerable<Employee> ems = items as IEnumerable<Employee>;
    return ems.Select(em => new
    {
        id = em.EmployeeID,
        name = em.FirstName
    }
    ).ToArray();
}

The parameter object items is IEnumerable of EntityObject, and the function will be executed at client side memorry and shall have nothing to do with database now.
But I don't know the EntityObject type (Employee) until runtime, so maybe some complex reflection will be used.
I have checked this, but when I bind the result to the control, it showed only blank rows without any column or data. And the funciton is for IQueryable, I have tried IEnumerable.AsQueryable and pass to it, but the results did not show any column either.

Community
  • 1
  • 1
Lei Yang
  • 3,970
  • 6
  • 38
  • 59
  • 1
    You might be able to modify the method `GetAccessExpression()` that's in an older answer of mine at http://stackoverflow.com/a/17772023/425871 Reflection isn't really too difficult to find a property specified as a string (like in your example) on an object that you don't know the type of, and even do it recursively (so you can access properties of properties). That method returns an `Expression` object to access the property, but it could return the value of the property instead. – Steve Dec 29 '13 at 04:55
  • @Steve Thanks, but private static Expression GetAccessExpression(Expression param, string property, Type type) this function is too different from what I want. I'm not able to convert it to public object SelectNew(object items, string[] fields). Any ideas? – Lei Yang Dec 29 '13 at 05:27

1 Answers1

1

I've modified the example I pointed to in my comment above. This actually returns an IEnumerable<Dictionary<string,object>>, where each Dictionary represents one of the "new objects", and each key value pair in the dictionary represents a property and its value. Perhaps you can modify this for your use?

I'm not sure if you can simply bind the result to the DataGrid, but you should be able to figure it out.

I don't believe it's possible to create an anonymous type on the fly... But it might be possible to change this to use a dynamic type like ExpandoObject instead of a Dictionary. See this question for some hints on how to do that. I've never used dynamic objects, so you're on your own there!

public class TestClassA {
    public string SomeString { get; set; }

    public int SomeInt { get; set; }

    public TestClassB ClassB { get; set; }
}

public class TestClassB {
    public string AnotherString { get; set; }
}

public class Program {

    private static void Main(string[] args) {
        var items = new List<TestClassA>();
        for (int i = 0; i < 9; i++) {
            items.Add(new TestClassA {
                SomeString = string.Format("This is outer string {0}", i),
                SomeInt = i,
                ClassB = new TestClassB { AnotherString = string.Format("This is inner string {0}", i) }
            });
        }

        var newEnumerable = SelectNew(items, new string[] { "ClassB.AnotherString" });
        foreach (var dict in newEnumerable) {
            foreach (var key in dict.Keys)
                Console.WriteLine("{0}: {1}", key, dict[key]);
        }

        Console.ReadLine();
    }

    public static IEnumerable<Dictionary<string, object>> SelectNew<T>(IEnumerable<T> items, string[] fields) {
        var newItems = new List<Dictionary<string, object>>();
        foreach (var item in items) {
            var dict = new Dictionary<string, object>();
            foreach (var field in fields)
                dict[field] = GetPropertyValue(field, item);
            newItems.Add(dict);
        }
        return newItems;
    }

    private static object GetPropertyValue(string property, object o) {
        if (property == null)
            throw new ArgumentNullException("property");
        if (o == null)
            throw new ArgumentNullException("o");

        Type type = o.GetType();

        string[] propPath = property.Split('.');
        var propInfo = type.GetProperty(propPath[0]);

        if (propInfo == null)
            throw new Exception(String.Format("Could not find property '{0}' on type {1}.", propPath[0], type.FullName));

        object value = propInfo.GetValue(o, null);

        if (propPath.Length > 1)
            return GetPropertyValue(string.Join(".", propPath, 1, propPath.Length - 1), value);
        else
            return value;
    }
}
Community
  • 1
  • 1
Steve
  • 6,334
  • 4
  • 39
  • 67