Советы по деревьям выражений C # - PullRequest
3 голосов
/ 01 октября 2008

Я работаю над методом, который принимает дерево выражений в качестве параметра вместе с типом (или экземпляром) класса.

Основная идея заключается в том, что этот метод добавит определенные вещи в коллекцию, которая будет использоваться для проверки.

public interface ITestInterface
{
    //Specify stuff here.
}

private static void DoSomething<T>(Expression<Func<T, object>> expression, params IMyInterface[] rule)
{
    // Stuff is done here.
}

Метод вызывается следующим образом:

class TestClass
{
    public int MyProperty { get; set; }
}

class OtherTestClass  : ITestInterface
{
    // Blah Blah Blah.
}

static void Main(string[] args)
{
    DoSomething<TestClass>(t => t.MyProperty, 
        new OtherTestClass());
}

Я делаю это таким образом, потому что хотел бы, чтобы переданные имена свойств были строго напечатаны.

Пара вещей, с которыми я борюсь ..

  1. В DoSomething я хотел бы получить тип PropertyInfo (из переданного тела) T и добавить его в коллекцию вместе с правилом []. В настоящее время я думаю об использовании expression.Body и удалении [propertyname] из «Convert. ([Propertyname])» и использовании отражений, чтобы получить то, что мне нужно. Это кажется громоздким и неправильным. Есть ли лучший способ?
  2. Это определенный шаблон, который я использую?
  3. И, наконец, приветствуются любые предложения или разъяснения относительно моего неправильного понимания того, что я делаю, и / или ресурсы или хорошая информация о деревьях выражений C #.

Спасибо!

Ian

Edit:

Примером того, что expression.Body.ToString() возвращает в методе DoSomething, является строка, которая содержит «Convert (t.MyProperty)» при вызове из примера выше.

Мне нужно, чтобы он был строго напечатан, поэтому он не будет компилироваться, если я изменю имя свойства.

Спасибо за предложения!

Ответы [ 3 ]

3 голосов
/ 08 января 2009

Я в значительной степени полагаюсь на деревья выражений, чтобы подтолкнуть большую часть того, что я хочу сделать с моим текущим приложением, во время компиляции, то есть статическую проверку типов.

Я пересекаю деревья выражений, чтобы перевести их во что-то еще, что «имеет смысл».

Одна вещь, которую я часто делал, заключается в том, что вместо URL я полагаюсь на MVC-подобный подход, где я объявляю лямбда-функции и транслирую это ... интерпретировать, сгенерированное компилятором дерево выражений в URL. Когда этот URL вызывается, я делаю наоборот. Таким образом, у меня есть то, что я называю проверками во время компиляции для битых ссылок, и это прекрасно работает с рефакторингом и перегрузками. Я думаю, это здорово думать об использовании деревьев выражений таким образом.

Возможно, вы захотите проверить шаблон посетителя, с чего начинать очень трудно, потому что вначале он не имеет особого смысла, но он связывает все воедино и это очень формальный способ решения проверки типов в конструкции компилятора. Вы можете сделать то же самое, но вместо проверки типов выведите все, что вам нужно.

Что-то, против чего я сейчас вхожу, - это возможность создать простую структуру для перевода (или, на самом деле, я должен сказать, интерпретировать) выражений Tress и испускания JavaScript. Идея состоит в том, что сгенерированные компилятором деревья выражений преобразуются в действительный JavaScript, который взаимодействует с некоторой объектной моделью.

Что удивительно в этом, так это то, что компилятор всегда может сообщить мне, когда я ошибаюсь, и уверен, что конечный результат - это просто набор строк, но важная часть заключается в том, как эти строки были созданы. Они прошли некоторую проверку, и это что-то значит.

Как только вы начнете это делать, вы мало что сможете сделать с деревьями выражений.

Работая с материалом System.Reflection.Emit, я обнаружил, что использую деревья выражений для создания облегченного фреймворка для динамической компиляции, который во время компиляции может в основном сказать, будут ли компилироваться мои динамически созданные сборки, и это сработало легко с отражением и статической проверкой типа. Это пошло дальше и дальше, и в итоге получилось нечто, что в итоге сэкономило много времени и оказалось очень проворным и надежным.

Так что мне нравятся такие вещи, и это то, чем занимается метапрограммирование, написание программ в ваших программах, которые делают программы. Я говорю, продолжай!

2 голосов
/ 01 октября 2008

Я ценю то, что вы пытаетесь сделать с собственностью здесь. Я столкнулся с этой загадкой. Всегда странно писать:

DoSomething("MyProperty", new OtherClass());

Если свойство когда-либо меняет имя или в вызове вводится неверный текст, тогда возникнет проблема. Я пришел к выводу, что это то, с чем вам, вероятно, придется столкнуться при тестировании. В частности, модульное тестирование. Я бы написал модульные тесты, чтобы убедиться, что вызовы DoSomething работают правильно.

Другая вещь, которую вы можете попробовать, это украсить ваши свойства атрибутами, а затем отразить свой класс, когда он создается, искать свойства с атрибутом и загружать правила.

[DoSomething(typeof(OtherClass), typeof(OtherClass2))]
public int MyProperty
{
  get;
  set;
}

В этом случае конструктор (возможно, в базовом классе?) Будет динамически создавать объект OtherClass и объект OtherClass2 и загружать их в коллекцию вместе с именем свойства.

2 голосов
/ 01 октября 2008

Сбор объектов PropertyInfo из Expression.Body выглядит как мое решение с другим вопросом.

...