Вопрос

Я добавляю интерфейс LINQ к некоторым пользовательским объектам, но Компилятор C# не выполняет вывод типа.Однако я могу написать эквивалентный запрос, используя необработанные методы расширения, и вывод типа будет успешным, поэтому я не уверен, как компилятор преобразует выражение запроса в вызовы методов расширения.

Есть ли инструмент или флаг компилятора, чтобы я мог видеть, что компилятор генерирует из моего выражения запроса, и разобраться в этом?

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

Это было полезно?

Решение

Ваш код понимания запроса:

from f1 in e1
from f2 in e2
from f3 in e3
select f3

Код вызова вашего метода:

e1
.SelectMany(f1 => e2)
.SelectMany(f2 => e3), (f2, f3) => f3))

Трансляция запроса происходит следующим образом.Сначала разберемся с первыми двумя из предложений:

from f1 in e1
from f2 in e2
from f3 in e3
select f3;

Это переведено на

from x in ( e1 ) . SelectMany( f1 => e2 , ( f1 , f2 ) => new { f1 , f2 } )
from f3 in e3
select f3;

Где «x» — прозрачный идентификатор.Поскольку ни один из e1, e2 или e3 не использует какую-либо переменную диапазона, тот факт, что это прозрачный идентификатор, не имеет значения;для обработки семантики прозрачного идентификатора не требуется никаких дополнительных переписываний.

Затем этот результат преобразуется в

( ( e1 ) . SelectMany( f1 => e2 , ( f1 , f2 ) => new { f1 , f2 } ) ) 
.SelectMany( x => e3 , ( x , f3 ) => f3 )

Мы можем убрать некоторые из этих скобок:

e1 
.SelectMany( f1 => e2 , ( f1 , f2 ) => new { f1 , f2 } ) ) 
.SelectMany( x => e3 , ( x , f3 ) => f3 )

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

e1
.SelectMany(f1 => e2)
.SelectMany(f2 => e3), (f2, f3) => f3))

Если вы подставите e1, e2, e3 в фактическое синтаксическое преобразование, описанное выше, пройдет ли полученное выражение выведение типа?

Если это не так, то вопрос: «Почему бы и нет?» Либо что -то не так с вашим кодом, либо что -то не так с типом InferRer.Если что-то не так с устройством вывода типа, дайте мне знать.

Если да, то возникает вопрос: «Что не так с этапом синтаксического преобразования»?Если что-то не так с этапом синтаксического преобразования, дайте мне знать.

Спасибо!

Другие советы

Вы можете использовать Отражатель и просмотрите свой код с отключенной оптимизацией.

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

from x in Foo.Bar()
...

Foo.Bar() должен был возвращать Future, а x также должен был иметь тип Future, но это не работает с переводом запроса.Я решил эту проблему, добавив еще один уровень косвенности, по сути оборачивая фьючерсы, скажем, в тип Async<T>, экземпляр которого можно было создать только с помощью фьючерсов, т.е.

public sealed class Async<T> { internal T value; }
public static class Async
{
   public static Async<Future<T>> Begin<T>(Future<T> future) { ... }
}

Затем я могу написать вычисления запроса для значений Async, чтобы выражение выглядело примерно так:

from x in Async.Begin(Foo.Bar())
...

где x теперь имеет тип будущего, и я могу произвольно принудительно принудительно или отложить фьючерсы и обещания.

Спасибо всем за предложения.Однако переводчик выражений запросов, встроенный в Visual Studio, был бы полезен, если кто-нибудь из MS это читает.;-)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top