Предположим, что у меня есть класс:
class MyClass {
public int MyMethod(Func<int, int> f) { return 0; }
public int MyMethod(Expression<Func<int, int>> f) { return 1; }
}
Когда я пытаюсь вызвать метод с выражением лямбда, я получаю ошибку компиляции, заявляя, что вызов неоднозначен между двумя перегрузками:
var myClass = new MyClass();
myClass.MyMethod(x => 1 + x); // Error!
в то время как, конечно, вызов с явным типом работает нормально:
myClass.MyMethod((Func<int, int>)(x => 1 + x)); // OK, returns 0
myClass.MyMethod((Expression<Func<int, int>>)(x => 1 + x)); // OK, returns 1
Дерево выражений содержит больше информации (фактический код), и я могу использовать эту информацию, когда она доступна. Но я также хочу, чтобы мой код работал с делегатами. К сожалению, эта двусмысленность делает это, поэтому я должен найти другой способ различать два вызова, которые испортили иначе чистый API.
Спецификация С# ничего не говорит об этой конкретной ситуации, поэтому в этом смысле поведение действительно соответствует спецификации.
Однако есть аргумент, который следует сделать, чтобы дерево выражений было предпочтительнее делегата. Метод Compile
действует как явное преобразование из дерева выражений в делегат. Дерево выражений содержит больше информации, и когда вы компилируете делегата, вы теряете эту информацию. В другом направлении нет конверсии.
Есть ли какие-либо причины не предпочитать дерево выражений?