从匿名类型获取字段

时间:2014-07-07 14:41:28

标签: c# anonymous-types

我有这个班:

public class allFields
{
    public string EAN { get; set; }
    public string title { get; set; }
    public string qty { get; set; }
    public string price { get; set; }
    public DateTime date { get; set; }
}

返回匿名类型的函数:

public IEnumerable<object> stockEtatQty()
{   
    List<allFields> afList = new List<allFields>();

    var query = from x in ctx.book
                where x.qty > 0
                select x;
    foreach (var item in query)
    {
        allFields af = new allFields();
        af.EAN = item.EAN;
        af.title = item.Titre;
        af.qty = ""+item.Quantite;
        afList.Add(af);
    }
    var q = from x in afList
            select new { EAN=x.EAN, Title=x.title, Quantity=x.qty };

    return q; //q is a IEnumerable<'a> where a is new {string EAN, string Title, string Quantity}
}

在我的WinForm中,使用以下函数:

private void QuantityToolStripMenuItem_Click(object sender, EventArgs e)
{
    ServiceStock sstock = new ServiceStock();
    var q = sstock.stockEtatQty().ToList();// q is a list<object>
    string str = "";
    foreach (var item in q)
    {
        str += item + Environment.NewLine;
    }
    MessageBox.Show(str);
}

结果是:

{ EAN = 1, Title = CSharp Security, Quantity = 970 }
{ EAN = 2, Title = MISC, Quantity = 100 }
...

我想要什么?
我想要不喜欢上面的结果,但要将循环item中的foreach的每个字段分开,例如获取item.EANitem.Titleitem.Quantity。< / p>

如果我的问题没有解决方案,我想知道一个替代方案,
谢谢你的帮助。

4 个答案:

答案 0 :(得分:2)

显而易见的解决方案是创建自定义类型(让我们称之为BookInfo)并返回IEnumerable<BookInfo>而不是IEnumerable<object>(如果您需要,可以覆盖ToString将格式放入此类本身)。

然后您可以轻松格式化输出。

public class BookInfo
{
    public string EAN {get;set;}
    public string Title {get;set;}
    public int Quantity {get;set;}
}

public IEnumerable<BookInfo> stockEtatQty()
{   
    ...

    var q = from x in afList
            select new BookInfo { EAN=x.EAN, Title=x.title, Quantity=x.qty };

    return q;
}

private void QuantityToolStripMenuItem_Click(object sender, EventArgs e)
{
    ServiceStock sstock = new ServiceStock();
    var q = sstock.stockEtatQty();

    var message = string.Join(Environment.NewLine, 
                              q.Select(item => String.Format("{0} {1} {2}", item.EAN, item.Title, item.Quantity)));
    MessageBox.Show(message);
}

答案 1 :(得分:1)

由于在您退出stockEtatQty()方法时,有关匿名类型对象的静态类型信息会丢失,您可以将对象强制转换为dynamic并访问如下字段:

str = string.Join(Environment.NewLine, q.Cast<dynamic>().Select(item => 
    string.Format("{0} {1} {2}", item.EAN, item.Title, item.Quantity)
));

转换为dynamic告诉编译器需要在运行时解析EANTitleQuantity

请注意,我还通过调用foreach替换了string.Join循环以提高性能:重复的字符串连接会创建不必要的部分字符串对象,string.Join会避免这种情况。另一种解决方案是使用StringBuider而不是字符串连接+=

  

stockEtatQty在项目(服务)中,QuantityToolStripMenuItem_Click在另一个项目中(查看)

不幸的是,这意味着您将无法使用匿名类型:使用内部可见性生成匿名类型,将其使用限制在生成它们的程序集中。您可以根据this answer中描述的ExpandoObject使用变通方法

var q = afList.Select(x => {
    dynamic res = new ExpandoObject();
    res.EAN=x.EAN;
    res.Title=x.title;
    res.Quantity=x.qty;
    return res;
});

答案 2 :(得分:0)

您可以使用动态对象集合而不是简单对象作为方法的返回类型:

public IEnumerable<dynamic> stockEtatQty()

然后您将没有IntelliSense,但在运行时将找到属性:

foreach (var item in sstock.stockEtatQty())    
    str += String.Format("{0}", item.EAN) + Environment.NewLine;

但我建议您使用EAN,Title和Quantity属性创建自定义类。或者只使用您的allFields而不是匿名对象。


还要考虑使用StringBuilder进行字符串创建,以避免创建大量的内存中字符串:

var builder = new StringBuilder();
foreach (var item in sstock.stockEtatQty())
   builder.AppendFormat("{0}{1}", item.EAN, Environment.NewLine);

MessageBox.Show(builder.ToString());

答案 3 :(得分:0)

创建一个表示新对象结构的新类并返回该对象。

var q = from x in afList
        select new SmallerType { EAN=x.EAN, Title=x.title, Quantity=x.qty };

WinForm功能

foreach (SmallerType item in q)
{
  //
}