Можно ли вызывать методы расширения Rx с помощью лямбда-выражений из скрипта IronPython?

Может кто-нибудь объяснить мне это действительно странное наблюдение?

Я пытался вызывать методы расширения Rx изнутри IronPython, и это оказалось просто невозможным. Я свел это к этому простому примеру:

import clr
clr.AddReference("System.Core")
from System.Linq import Enumerable

def process(value):
  return Enumerable.Select(value, lambda x:x)

В этом случае мы начинаем с обычного LINQ. Если я вызываю функцию process из своей среды хостинга с массивом или любым другим объектом IEnumerable, она работает совершенно нормально.

Затем я попытался просто заменить ссылки, чтобы использовать методы расширения Observable, например:

import clr
clr.AddReference("System.Reactive.Linq")
from System.Reactive.Linq import Observable

def process(value):
  return Observable.Select(value, lambda x:x)

В этом случае, если я вызову функцию process с объектом IObservable, вызов завершится с уродливым сообщением об ошибке:

expected IObservable[object], got Select[int, int]

Кто-нибудь наткнулся на что-то подобное? Я что-то пропустил? Есть ли какой-то особый случай, чтобы заставить Enumerable работать с лямбда-делегатами, которых нет Observable? Должен признаться, я здесь совершенно сбит с толку.

Кстати, в качестве проверки работоспособности отлично работает следующий пример:

import clr
clr.AddReference("System.Reactive.Linq")
from System.Reactive.Linq import Observable

def process(value):
  return Observable.Sum(value)

Я хотел оставить это там, просто чтобы было ясно, что проблема действительно в вызове метода Observable.Select.


person glopes    schedule 14.01.2017    source источник
comment
Я отправил проблему в репозиторий IronPython с дополнительными выводами. Теперь я считаю, что это более общая ошибка с разрешением вызова метода IronPython, но все же был бы признателен за более глубокое понимание проблемы.   -  person glopes    schedule 14.01.2017


Ответы (1)


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

Из сообщения об ошибке кажется, что вы пытаетесь вызвать его на IObservable<int>. Похоже, здесь не работает разрешение перегрузки, и он пытается вызвать его как Observable.Select<object, object>(). Вам нужно будет дать несколько советов о том, какую перегрузку вы хотите использовать.

def process(value):
    return Observable.Select[int,int](value, Func[int,int](lambda x:x))
person Jeff Mercado    schedule 17.01.2017
comment
Отлично, это сработало, и на самом деле в этом случае вам даже не нужны явные типы для универсального метода: достаточно явно ввести лямбду. Тогда возникает вопрос, почему это не нужно для класса Enumerable, где методы имеют одинаковые перегрузки (например, лямбда-выражения с разными номерами аргументов). - person glopes; 17.01.2017
comment
Если бы мне пришлось рискнуть предположить, наблюдаемый экземпляр, переданный в реализацию, реализует множество, возможно, конфликтующих интерфейсов, и, должно быть, столкнулся с ситуацией, когда он не знал, как решить, какой тип должен принимать лямбда. Большинство коллекций просты, поэтому легче найти лучшую перегрузку. Я не могу проверить это сейчас, но, возможно, есть явно реализованный интерфейс, который где-то использует object, и он использовал это. - person Jeff Mercado; 18.01.2017
comment
На самом деле, я понимаю тот очевидный факт, что IronPython не может определить тип любой лямбды так, как это делает LINQ, даже в случае Enumerable.Select. Учитывая, что python по своей сути является динамическим языком, тело селектора в принципе может каждый раз возвращать что угодно, поэтому единственным разумным типом возврата является object. Так много для написания сценариев LINQ таким образом. - person glopes; 18.01.2017