Почему аргументы лямбда выражения неоднозначны между Func и Expression?

Предположим, у меня есть класс:

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 действует как явное преобразование из дерева выражений в делегат. Дерево выражений содержит больше информации, и при компиляции в делегат эта информация теряется. В другом направлении преобразования нет.

Есть ли причины не отдавать предпочтение дереву выражений?

23
задан John Saunders 26 November 2011 в 19:24
поделиться