Предположим, у меня есть класс:
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.
В спецификации C# ничего не говорится об этой конкретной ситуации, так что в этом смысле поведение соответствует спецификации.
Однако есть аргумент в пользу того, что дерево выражений должно быть предпочтительнее делегата. Метод Compile
действует как явное преобразование из дерева выражений в делегат. Дерево выражений содержит больше информации, и при компиляции в делегат эта информация теряется. В другом направлении преобразования нет.
Есть ли причины не отдавать предпочтение дереву выражений?