Какой хороший вариант использования для .net 4.0 Expression Trees?
Этот был вдохновлен моим коллегой по языковому гуру, который не может показаться им полезным, и после нескольких неудачных попыток я должен согласиться.
Теперь я знаю, что эти концепции, как правило, становятся намного легче, когда вы получаете некоторые хорошие практические причины.
На данный момент кажется, что его единственная цель - позволить вам написать поставщика Linq?
Это что? Есть ли другие преимущества для этого?
Ответы
Ответ 1
Дерево выражений настолько мощное, что позволяет обрабатывать код как данные. Пользователи привыкли собирать данные, сохранять их и возвращаться к ним позже.
Деревья выражений позволяют делать то же самое с кодом. Например, вы можете ввести свой пользовательский ввод (флажки, диапазоны номеров и т.д.) И перевести его в дерево выражений. Это дерево выражений может быть выполнено или сохранено для последующего использования. Очень круто.
Подумайте о практическом использовании отчетов, таких как создание и сохранение фильтров данных и сопоставлений данных. Другим практическим применением будет поддержка пользовательских рабочих потоков в вашем приложении на основе пользовательских правил.
Здесь немного кода MSDN для сериализации деревьев выражений (http://code.msdn.microsoft.com/exprserialization), которые должны генерировать идеи.
Ответ 2
Вы можете использовать деревья выражений для преобразования языка домена в исполняемый код.
Ответ 3
Решение, ищущее проблему eh?
Деревья выражений позволяют представить код как преобразуемую структуру данных, поэтому они идеально подходят для преобразования между языками Linq To SQL, являющимся наиболее мощным в настоящее время.
Другое использование, помимо DSL (которое является преобразованием), - это распараллеливание (которое разделяется), а пример в этом пространстве - PLINQ.
Ответ 4
.NET 4.0 Деревья выражений также являются основой для DLR AST
Ответ 5
Быстрый ответ: "Нет, это не только для поставщиков LINQ сейчас". Во-первых, деревья выражений были расширены динамическим языком для поддержки динамических языков. В принципе, если вы хотите портировать свой собственный динамический язык на .NET(например, IronPython и IronRuby), вам придется использовать деревья выражений.
Хорошо, не так много людей имеют свои языки. Каковы другие варианты использования? Один из них - генерировать динамический код во время выполнения. У меня есть пример: Создание динамических методов с деревьями выражений в Visual Studio 2010. В нем объясняется, как использовать ET вместо генерации MSIL для создания динамических методов.
На самом деле, существуют некоторые примеры использования деревьев выражений вне LINQ даже в .NET 3.5, но эти записи еще не записаны.
Ответ 6
У меня был хороший опыт с тем, чтобы преобразовать АСТ в доменные имена в деревья выражений. Это также довольно легко с помощью ANTLR адаптера дерева для создания дерева выражений непосредственно из грамматики.
Ответ 7
см. эту запись: http://codebetter.com/blogs/gregyoung/archive/2009/10/03/delegate-mapper.aspx
Это отличный вариант использования.
Ответ 8
Вы можете использовать дерево выражений в качестве построителя кода с более высоким уровнем абстракции, а затем сгенерировать сборку и быстрее, чем CodeCompiler. Вот некоторые доказательства концепции, которую я использовал, чтобы убедить нашу команду использовать их в качестве замены CodeCompiler.
[TestClass]
public class WhenINeedToAccessPropertiesByNameHavingATypeReference
{
public class SomeCategoryData
{
public DateTime CreatedDate { get; set; }
}
[TestMethod]
public void ICanDoThatWithAnExpressionAndItPerformsWell()
{
// INIT
var someCategoryData =
Enumerable.Range(1970, 100).Select(year =>
new SomeCategoryData { CreatedDate = new DateTime(year, 1, 1) }).Cast<object>();
var t = typeof(SomeCategoryData); // or it can be: t = someCategoryData.First().GetType();
var compiled = Stopwatch.StartNew();
// ACT
var filter = AccessPropertyByNameInCompiledMannerSomehow(t, "CreatedDate");
// ASSERT
Trace.WriteLine(string.Format("compiled in: {0}", compiled.Elapsed));
Assert.IsTrue(compiled.ElapsedMilliseconds < 3, "compiles fast enough");
var executed = Stopwatch.StartNew();
// ACT
List<object> result = null;
for (var i = 0; i < 10000; i++)
{
result = someCategoryData.Where(d => filter(d, new DateTime(2000, 1, 1), new DateTime(2009, 1, 1)))
.ToList();
}
executed.Stop();
Trace.WriteLine(string.Format("executed in: {0}", executed.Elapsed));
// ASSERT
Assert.AreEqual(10, result.Count, "insure compiled code actually works");
Assert.IsTrue(executed.ElapsedMilliseconds < 300, "runs fast enough");
}
private static Func<object, DateTime, DateTime, bool>
AccessPropertyByNameInCompiledMannerSomehow(Type t, string fieldToFilterBy)
{
var objectParameter = Expression.Parameter(typeof(object), "p");
var instance = Expression.Convert(objectParameter, t);
var lower = Expression.Parameter(typeof(DateTime), "l");
var upper = Expression.Parameter(typeof(DateTime), "u");
var composite = Expression.Lambda<Func<object, DateTime, DateTime, bool>>(
Expression.And(
Expression.LessThanOrEqual(
lower,
Expression.PropertyOrField(instance, fieldToFilterBy)
),
Expression.GreaterThanOrEqual(
upper,
Expression.PropertyOrField(instance, fieldToFilterBy)
)
), objectParameter, lower, upper
);
return composite.Compile();
}
}
Ответ 9
У меня есть несколько примеров здесь
(извините за форматирование разбитого кода)