繁体   English   中英

从匿名类型获取字段

[英]Get fields from anonymous type

我有这个课:

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

我想要的是?
我不喜欢上面的结果,但是在foreach循环中将item每个字段分开,例如get item.EANitem.Titleitem.Quantity

如果无法解决我的问题,我想知道一个替代方法,
感谢帮助。

显而易见的解决方案是创建一个自定义类型(我们将其称为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);
}

由于在退出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需要在运行时解析。

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

stockEtatQty在一个项目中(服务), QuantityToolStripMenuItem_Click在另一个项目中(视图)

不幸的是,这意味着您将无法使用匿名类型:匿名类型是在内部可见的情况下生成的,将它们的使用限制在生成它们的程序集中。 您可以根据此答案中所述的ExpandoObject使用解决方法:

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

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

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

创建一个表示新对象结构的新类,然后将其返回。

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

WinForm函数

foreach (SmallerType item in q)
{
  //
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM