动态LINQ:在新子句中指定类名
使用Dynamic LINQ,需要对给定类的字段进行哪些更改?
例如,如何在DLinq中重现以下C#查询:
var carsPartial = cars.Select(c => new {c.year, c.name, make = new maker() {name = c.make.name} }).ToList();
我已应用此答案https://stackoverflow.com/a/1468357/288747中提到的更改,以允许返回类型为调用类型而不是匿名类型。
类定义如下(如果有帮助):
class car { public int vid; public int odo; public int year; public string name; public maker make; } class maker { public string name; public int firstYear; }
以下不起作用(但我认为很接近,但仍然不起作用,因为我没有动态linq库所需的更改,这是我需要的):
var carsPartial = cars.Select("new(name, year, new maker() {name = make.name})").ToList();
但它失败了new maker() {
(如预期的那样)。
我确定我需要更改DynamicLibrary.cs
以使其工作,并且可以在如何改变它以实现此目的方面做一些指导。
更新 :我已将我的答案转变为更广泛的博客文章 。
我还没有真正使用过Dynamic Linq库,但是我已经看了一下DynamicLibrary.cs代码以及支持生成类型类的更改,这些类是在您提供的链接中提供的另一个stackoverflow问题中提供的。 分析它们,似乎嵌套的new
-s应该在配置中开箱即用。
但是,您的查询似乎不是正确的Dynamic Linq的语言查询。 请注意,DLinq的查询字符串不等同于C#并且具有自己的语法。
我认为,查询应该读出以下内容:
var carsPartial = cars.Select("new(name, year, new maker(make.name as name) as make)").ToList();
编辑:
我意识到,重新阅读这个stackoverflow问题 ,它实际上并没有扩展Dynamic Linq的语言,有可能创建新的强类型类。 他们只是将结果放到指定为Select()
的generics参数的类中,而不是在查询字符串中指定它。
为了获得您需要的东西,您需要恢复他们的更改(获得通用DLinq)并应用我的更改,我刚刚validation了工作:
找到ExpressionParser
类的ParseNew
方法并将其更改为以下内容:
Expression ParseNew() { NextToken(); bool anonymous = true; Type class_type = null; if (token.id == TokenId.Identifier) { anonymous = false; StringBuilder full_type_name = new StringBuilder(GetIdentifier()); NextToken(); while (token.id == TokenId.Dot) { NextToken(); ValidateToken(TokenId.Identifier, Res.IdentifierExpected); full_type_name.Append("."); full_type_name.Append(GetIdentifier()); NextToken(); } class_type = Type.GetType(full_type_name.ToString(), false); if (class_type == null) throw ParseError(Res.TypeNotFound, full_type_name.ToString()); } ValidateToken(TokenId.OpenParen, Res.OpenParenExpected); NextToken(); List properties = new List (); List expressions = new List (); while (true) { int exprPos = token.pos; Expression expr = ParseExpression(); string propName; if (TokenIdentifierIs("as")) { NextToken(); propName = GetIdentifier(); NextToken(); } else { MemberExpression me = expr as MemberExpression; if (me == null) throw ParseError(exprPos, Res.MissingAsClause); propName = me.Member.Name; } expressions.Add(expr); properties.Add(new DynamicProperty(propName, expr.Type)); if (token.id != TokenId.Comma) break; NextToken(); } ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected); NextToken(); Type type = anonymous ? DynamicExpression.CreateClass(properties) : class_type; MemberBinding[] bindings = new MemberBinding[properties.Count]; for (int i = 0; i < bindings.Length; i++) bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]); return Expression.MemberInit(Expression.New(type), bindings); }
然后,找到类Res
并添加以下错误消息:
public const string TypeNotFound = "Type {0} not found";
Etvoilà,您将能够构建如下查询:
var carsPartial = cars.Select("new(name, year, (new your_namespace.maker(make.name as name)) as make)").ToList();
确保包含完整的类型名称,包括整个命名空间+类路径。
为了解释我的变化,它只是检查new
括号和左括号之间是否有一些标识符(参见乞讨时添加的“if”)。 如果是这样,我们解析完整的点分隔类名,并尝试通过Type.GetType
获取其Type
,而不是在匿名new
s的情况下构建自己的类。
如果我已经正确地理解你,你想创建一个简单的匿名类,其中包含来自class car
和class maker
字段。 如果是这种情况,您可以在该类中提供新名称,如下所示:
var carsPartial = cars.Select(c => new { year = c.year, name = c.name, make_name = c.make.name });
甚至只为冲突的字段提供名称:
var carsPartial = cars.Select(c => new { c.year, c.name, make_name = c.make.name });
- 为什么每个Dispatcher.BeginInvoke回调都有一个唯一的同步上下文?
- ConfigurationManager.AppSettings是否在.NET Core 2.0中可用?
- 使用LINQ将XML解析为Dictionary
- 再访问Task.ConfigureAwait(continueOnCapturedContext:false)
- 自SQL 2008升级以来,SqlDataReader.HasRows返回false
- c#使json无法在视图中正确呈现
- 将非托管C ++指针转换为对象到托管C#对象
- 通过C#对XMPGPano元数据进行图像处理:用于facebook 360图像
- 我如何(优雅地)将字符串转换为字符串特定部分的标签?