Когда вы пишете запросы linq и анонимные объекты, компилятор скрывает много волшебства, которое он делает для вас.В частности, для анонимных объектов создает новые типы для вас.Если этот тип где-то не существует, вам нужно будет создать тип вручную и использовать его вместо него.
Вы можете немного обмануть и заставить компилятор создать объект с этим типом и сохранить ссылку на этот тип,При этом вы можете сгенерировать необходимые выражения для создания экземпляра этого объекта.
Следует отметить, что созданные для вас анонимные объекты будут иметь конструкторы с параметрами в порядке определения, поэтому вам просто нужно вызвать этот конструктор.
var keyType = new { Prop1=default(string), Prop2=default(string) }.GetType();
var ctor = keyType.GetConstructor(new Type[] { typeof(string), typeof(string) });
var param = Expression.Parameter(typeof(GraphData), "x");
var keySelector = Expression.Lambda(
Expression.New(ctor,
Expression.PropertyOrField(param, "Prop1"), // corresponds to Prop1
Expression.PropertyOrField(param, "Prop2") // corresponds to Prop2
),
param
); // returns non-generic LambdaExpression
Имейте в виду, что мы имеем дело с типами, не известными во время компиляции, поэтому ваше выражение селектора ключа не будет иметь тип времени компиляции.