ОБНОВЛЕНИЕ : я превратил свой ответ в чуть более обширный пост в блоге .
На самом деле я никогда не использовал библиотеку 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();
EDIT:
Перечитывая этот вопрос о стековом потоке Я осознаю, что более точно он не расширяет язык Dynamic Linq возможностью создания новых строго типизированных классов. Они просто помещают результат в класс, указанный как универсальный параметр Select()
, вместо того, чтобы указывать его в строке запроса.
Чтобы получить то, что вам нужно, вам нужно отменить их изменения (получить общий DLinq) и применить мои изменения, я только что проверил на работу:
Найдите метод ParseNew
класса ExpressionParser
и измените его на следующее:
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<DynamicProperty> properties = new List<DynamicProperty>();
List<Expression> expressions = new List<Expression>();
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";
Et voilà, вы сможете создавать запросы как:
var carsPartial = cars.Select("new(name, year, (new your_namespace.maker(make.name as name)) as make)").ToList();
Убедитесь, что вы включили полное имя типа, включая все пространство имен + путь к классу.
Чтобы объяснить мои изменения, он просто проверяет, есть ли какой-нибудь идентификатор между new
и открывающей скобкой (см. Добавленное «если» в начале). Если это так, мы анализируем полное имя класса через точку и пытаемся получить его Type
через Type.GetType
вместо создания собственного класса в случае анонимного new
s.