
知乎周源微信
NOTE: An alternative title to this post might be: "The Weekly Source Code 48: Making The Weekly Source Code 47 Suck Incrementally Less."
注意:此帖子的替代标题可能是:“每周源代码48:使每周源代码47逐渐减少。 ”
NOTE: This isn't a language feature! This works on both C# and VB!
注意:这不是语言功能! 这适用于C#和VB!
Last week I wrote a post about Dynamic Linq Query Generation in order to solve a kind of meta-programming problem. I had a site that used ASP.NET Dynamic Data and I wanted to do a LINQ query against some data. However, because I was creating a template that didn't know enough at compile time to write a proper LINQ query that could, well, compile, I needed to creating my LINQ dynamically.
上周,我写了一篇有关动态Linq查询生成的文章,以解决一种元编程问题。 我有一个使用ASP.NET动态数据的网站,我想对某些数据进行LINQ查询。 但是,由于我创建的模板在编译时不够了解,无法编写可以编译的正确LINQ查询,因此需要动态创建LINQ。
Be sure to hang in here with me, the awesome happens at the end.
一定要和我一起住在这里,这真是太棒了。
I was trying to generate effectively this, at runtime
我试图在运行时有效地生成此
Items.Select(row => row.Property).Distinct.OrderBy(colvalue => colvalue)
And I succeeded with Tatham Oddie's help in doing it this sub-optimal way:
在Tatham Oddie的帮助下,我以次优的方式成功做到了:
protected void Page_Init(object sender, EventArgs e) {
var items = Column.Table.GetQuery();
var entityParam = Expression.Parameter(Column.Table.EntityType, "row");
// row => row.Property
var columnLambda = Expression.Lambda(Expression.Property(entityParam, Column.EntityTypeProperty), entityParam);
// Items.Select(row => row.Property)
var selectCall = Expression.Call(typeof(Queryable), "Select", new Type[] { items.ElementType, columnLambda.Body.Type }, items.Expression, columnLambda);
// Items.Select(row => row.Property).Distinct
var distinctCall = Expression.Call(typeof(Queryable), "Distinct", new Type[] { Column.EntityTypeProperty.PropertyType }, selectCall);
// colvalue => colvalue
var sortParam = Expression.Parameter(Column.EntityTypeProperty.PropertyType, "sortValue");
var columnResultLambda = Expression.Lambda(sortParam, sortParam);
// Items.Select(row => row.Property).Distinct.OrderBy(colvalue => colvalue)
var ordercall = Expression.Call(typeof(Queryable), "OrderBy",
new Type[] { Column.EntityTypeProperty.PropertyType, columnResultLambda.Body.Type },
distinctCall, columnResultLambda);
var result = items.Provider.CreateQuery(ordercall);
foreach (var item in result) {
if (item != null) DropDownList1.Items.Add(item.ToString());
}
}
"Sub-optimal" is a programmer euphemism for crappy, hard to read, code that works. But what price my immortal soul?
“次优”是程序员的委婉说法,认为这些代码糟糕透了,难以阅读,并且有效。 但是我不朽的灵魂要付出什么代价呢?
Fortunately, Marcin from the ASP.NET team decided to come out of his apparent blogging vow of silence (lasting 18 months, no less) to save me.
幸运的是,来自ASP.NET团队的Marcin决定摆脱他明显的博客誓言(持续18个月,不少)以挽救我。
Marcin points out that there's a sample from 2006 released under the Ms-PL (how is anyone supposed to know this?) called DynamicQueryable. You actually have this on your hard drive NOW. It's under Samples\1033\CSharpSamples.zip\LinqSamples\DynamicQuery\DynamicQuery in your VS install directory.
Marcin指出,Ms-PL下有一个2006年发布的示例(应该怎么知道?),称为DynamicQueryable。 您现在实际上已经将其存储在硬盘上。 它位于VS安装目录中的Samples \ 1033 \ CSharpSamples.zip \ LinqSamples \ DynamicQuery \ DynamicQuery下。
In fact, His Gu-ness blogged about this in January of 2008 giving this VB example:
实际上,他的Gu-ness在2008年1月写了有关此VB示例的博客:
Dim Northwind As new NorthwindDataContext
Dim query = From p In Northwind.Products
Where p.CategoryID = 2 And UnitPrice > 3
Order By p.SupplierID
Select p
GridView1.DataSource = query
GridView1.DataBind()
But using the DynamicQuery library you can express the same thing like this, allowing for more dynamism. (Is that a word?)
但是使用DynamicQuery库,您可以像这样表达相同的内容,从而实现更多的动态性。 (这是一个字吗?)
Dim Northwind As new NorthwindDataContext
Dim query = Northwind.Products
.Where("CategoryID=2 And p.UnitPrice>3")
.OrderBy("SupplierID")
GridView1.DataSource = query
GridView1.DataBind()
Again, this works great when you don't know every input ahead of time. Marcin says:
同样,当您不提前知道所有输入时,此方法就很好用。 Marcin说:
DynamicQueryable is quite powerful and includes the following
DynamicQueryable功能非常强大,包括以下内容
Dynamic string-based querying of any LINQ provider (late-bound versions of Where, Select, OrderBy, Take, Skip, GroupBy, Any, and Count extension methods)
基于动态字符串的任何LINQ提供程序查询( Where , Select , OrderBy , Take , Skip , GroupBy , Any和Count扩展方法的最新版本)
String-based mini expression language (like the “it” identifier in the sample below), including complex conditional statements and all operators
基于字符串的小型表达式语言(如下面示例中的“ it”标识符),包括复杂的条件语句和所有运算符
Dynamic creation of classes for projections
动态创建投影类
Now Marcin was able to rewrite my pile of Expression crap above into this luscious four line snippet. The DynamicQueryable magic is the "var result =" line.
现在,Marcin可以将我上面的表达式废话重写为这个甜美的四行代码片段。 DynamicQueryable的法宝是“ var result =“行。
protected void Page_Init(object sender, EventArgs e) {
var items = Column.Table.GetQuery();
var result = items.Select(Column.EntityTypeProperty.Name).Distinct().OrderBy("it");
foreach (var item in result) {
if (item != null) DropDownList1.Items.Add(item.ToString());
}
}
ScottGu also points to Joseph and Ben Albahari, authors of the C# 3.0 In a Nutshell book and their incredibly deep post on building type-safe predicate methods. Their PredicateBuilder is free in the LINQKit extension library and can really help out when you get even deeper into this topic.
ScottGu还指出了C#3.0简而言之书的作者Joseph和Ben Albahari,以及他们在构建类型安全谓词方法方面的深入研究。 他们的PredicateBuilder在LINQKit扩展库中是免费的,并且在您更深入地了解该主题时可以提供真正的帮助。
Oh, and seriously, stop what you're doing now and go download LINQPad, the Albahari's most wonderful gift to us all. Then, thank them, and tell them how awesome they are.
哦,很重要的是,停止您现在正在做的事情,然后下载LINQPad ,这是阿尔巴哈里给我们所有人最好的礼物。 然后,感谢他们,并告诉他们他们有多棒。
Enjoy!
请享用!
知乎周源微信