Ищете надежную, общую реализацию op_Dynamic - PullRequest
11 голосов
/ 20 февраля 2011

Мне не удалось найти надежную общую реализацию op_Dynamic: кто-нибудь может указать мне одну? До сих пор в поисках использовались только игрушки или реализации специального назначения, но я бы хотел иметь такой под рукой, который, скажем, сравнивает по прочности со статической динамической реализацией C # по умолчанию (т. Е. Обрабатывает множество / все случаи, вызовы отражения кеша) (это Прошло много времени с тех пор, как я смотрел на статическую динамику в C #, так что, прости меня, если мои утверждения о его возможностях неверны).

Спасибо!

Ответы [ 2 ]

10 голосов
/ 29 июля 2011

Существует модуль FSharp.Interop.Dynamic , для nuget, который должен надежно обрабатывать динамический оператор с помощью dlr.

Он имеет несколько преимуществ по сравнению со многими фрагментами.

  • Производительность, которую он использует Dynamitey для вызова dlr, который реализует кэширование и является .NETСтандартная библиотека
  • Обрабатывает методы, которые возвращают void, вы получите исключение привязки, если вы не отмените их результаты.
  • Dlr обрабатывает случай вызова делегата, возвращаемого функциейавтоматически, это также позволит вам сделать то же самое с FSharpFunc
  • Добавляет!?Префиксный оператор для обработки вызова непосредственно динамических объектов и функций, тип которых у вас отсутствует во время выполнения.

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

8 голосов
/ 20 февраля 2011

Вы никогда не сможете получить полностью общую реализацию оператора ?. Оператор может быть реализован по-разному для различных типов, где может потребоваться сделать что-то особенное в зависимости от типа:

  • Для Dictionary<T, R> вы хотите использовать функцию поиска в словаре
  • Для объектов SQL в моей статье, на которую вы ссылались, вы хотите, чтобы она использовала определенный API SQL
  • Для неизвестных объектов .NET вы хотите, чтобы он использовал .NET Reflection

Если вы ищете реализацию, которая использует Reflection, то вы можете использовать ту, которую я реализовал в F # привязке для MonoDevelop ( доступно на GitHub ). Он достаточно полон и обрабатывает доступ к свойствам, вызовы методов, а также статические члены. (Остальная часть связанного файла использует его для вызова внутренних членов компилятора F #). Он напрямую использует Reflection, поэтому он довольно медленный, но вполне функциональный.

Другой альтернативой может быть реализация оператора поверх .NET 4.0 Dynamic Language Runtime (чтобы он использовал тот же базовый API, что и dynamic в C # 4). Я не думаю, что где-то есть реализация этого, но вот простой пример того, как вы можете получить это:

#r "Microsoft.CSharp.dll"
open System
open System.Runtime.CompilerServices
open Microsoft.CSharp.RuntimeBinder

let (?) (inst:obj) name (arg:'T) : 'R =
  // Create site (representing dynamic operation for converting result to 'R 
  let convertSite = 
    CallSite<Func<CallSite, Object, 'R>>.Create //'
      (Binder.Convert(CSharpBinderFlags.None, typeof<'R>, null)) //'
  // Create site for the method call with single argument of type 'T
  let callSite = 
    CallSite<Func<CallSite, Object, 'T, Object>>.Create //'
      (Binder.InvokeMember
        ( CSharpBinderFlags.None, name, null, null, 
          [| CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null);
             CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) |]))
  // Run the method and perform conversion
  convertSite.Target.Invoke
    (convertSite, callSite.Target.Invoke(callSite, inst, arg))

let o = box (new Random())
let a : int = o?Next(10)

Это работает только для вызовов методов экземпляра с одним аргументом (Вы можете узнать, как это сделать, посмотрев код, сгенерированный компилятором C # для вызовов dynamic). Я предполагаю, что если вы смешаете полноту (из первого) с подходом к использованию DLR (во втором), вы получите самую надежную реализацию, какую только сможете получить.

РЕДАКТИРОВАТЬ: Я также отправил код в F # Snippets. Вот версия с использованием DLR: http://fssnip.net/2U, а вот версия из плагина F # (с использованием .NET Reflection): http://fssnip.net/2V

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...