【问题标题】:Select new {Unknown fields} from IEnumerable<UnknownType>从 IEnumerable<UnknownType> 中选择新的 {Unknown fields}
【发布时间】:2013-12-29 03:53:06
【问题描述】:

我正在使用 VS2010 和 EF4.0。目标是选择任何 IEnumerable 的字段,以便在 DataGridView 中显示。以Northwind.Employees为例,如下代码即可。

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

参数object itemsIEnumerable of EntityObject,该函数将在客户端内存中执行,现在与数据库无关。
但是我直到运行时才知道 EntityObject 类型(Employee),所以可能会用到一些复杂的反射。
我检查了this, 但是当我将结果绑定到控件时,它只显示没有任何列或数据的空白行。并且功能是for IQueryable,我试过IEnumerable.AsQueryable并传递给它,但结果也没有显示任何列。

【问题讨论】:

  • 您也许可以修改 GetAccessExpression() 的方法 GetAccessExpression() 这是我的旧答案 stackoverflow.com/a/17772023/425871 反射并不是很难找到指定为字符串的属性(就像在您的示例中一样) 在您不知道其类型的对象上,甚至递归地执行它(因此您可以访问属性的属性)。该方法返回一个Expression 对象来访问该属性,但它可以改为返回该属性的值。
  • @Steve 谢谢,但是 private static Expression GetAccessExpression(Expression param, string property, Type type) 这个函数和我想要的太不一样了。我无法将其转换为公共对象 SelectNew(对象项,字符串 [] 字段)。有什么想法吗?

标签: c# linq reflection datagridview expression


【解决方案1】:

我已经修改了我在上面的评论中指出的示例。这实际上返回了一个IEnumerable&lt;Dictionary&lt;string,object&gt;&gt;,其中每个字典代表一个“新对象”,字典中的每个键值对代表一个属性及其值。也许您可以修改它以供您使用?

我不确定你是否可以简单地将结果绑定到 DataGrid,但你应该能够弄清楚。

我不相信动态创建匿名类型是可能的...但是可以将其更改为使用动态类型,例如ExpandoObject,而不是字典。有关如何做到这一点的一些提示,请参阅this question。我从来没有使用过动态对象,所以你自己在那里!

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

【讨论】:

    猜你喜欢
    • 2017-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-25
    • 1970-01-01
    • 1970-01-01
    • 2010-11-01
    • 1970-01-01
    相关资源
    最近更新 更多