Метод расширения Reactive работает в сборке для net48, но вызывает MissingMethodException при целевой платформе netstandard2.0.

Вопрос или проблема

У меня есть метод расширения, определенный в библиотеке классов (назовем ее My.Extensions.Reactive):

public static class ObservableExtensions
{
    /// <summary>
    /// Возвращает последовательность, которая генерируется путем сравнения каждого значения, эмитируемого подлежащим Observable, с первым эмитированным значением.
    /// Первым элементом, эмитируемым этим Observable, является результат сравнения первого элемента с самим собой.
    /// </summary>
    public static IObservable<TResult> RelativeToFirst<TValue, TResult>(this IObservable<TValue> observable, Func<TValue, TValue, TResult> selector)
    {
        // .Publish гарантирует, что подлежащий поток не будет уничтожен, пока этот поток не отписан.
        return observable.Publish(published => published.Take(1)
            .CombineLatest(published)
            .Select(((TValue First, TValue Current) combined) => selector(combined.First, combined.Current)));
    }
}

У меня есть тестовый случай, определенный в проекте xUnit, который нацелен на .NET Framework 4.8.

public class ObservableExtensionsTests
{
    [Fact]
    public async Task RelativeToFirst()
    {
        var input = Observable.Range(5, 10);

        var expected = Observable.Range(0, 10);

        var result = input.RelativeToFirst((initial, current) => current - initial);

        Assert.Equal(await expected.ToArray(), await result.ToArray());
    }
}

Если My.Extensions.Reactive.csproj нацелен на net48, то тест проходит.

Я хочу, чтобы библиотека My.Extensions.Reactive нацелилась на netstandard2.0, чтобы я мог использовать ее в проектах, нацеленных на более новые версии .NET, при этом поддерживая .NET 4.8. Однако, когда я меняю ее TargetFramework на netstandard2.0 и переустанавливаю пакеты NuGet System.Reactive 6.0.1, тест, который все еще нацелен на net48, терпит неудачу, выдавая следующий вывод xUnit:

System.MissingMethodException
Метод не найден: 'System.IObservable`1<System.ValueTuple`2<!!0,!!1>> System.Reactive.Linq.ObservableEx.CombineLatest(System.IObservable`1<!!0>, System.IObservable`1<!!1>)'.
   в My.Extensions.Reactive.ObservableExtensions.<>c__DisplayClass2_0`2.<RelativeToFirst>b__0(IObservable`1 published)
   в System.Reactive.Linq.ObservableImpl.Multicast`3._.Run(Multicast`3 parent)
--- Конец трассировки стека из предыдущего местоположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   в System.Reactive.Subjects.AsyncSubject`1.GetResult()
   в My.Extensions.Reactive_Test.ObservableExtensionsTests.<RelativeToFirst>d__0.MoveNext() в redacted\ObservableExtensionsTests.cs:line 19
--- Конец трассировки стека из предыдущего местоположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   в Xunit.Sdk.TestInvoker`1.<>c__DisplayClass47_0.<<InvokeTestMethodAsync>b__1>d.MoveNext() в /_/src/xunit.execution/Sdk/Frameworks/Runners/TestInvoker.cs:line 259
--- Конец трассировки стека из предыдущего местоположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   в Xunit.Sdk.ExecutionTimer.<AggregateAsync>d__4.MoveNext() в /_/src/xunit.execution/Sdk/Frameworks/ExecutionTimer.cs:line 48
--- Конец трассировки стека из предыдущего местоположения, где возникло исключение ---
   в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   в Xunit.Sdk.ExceptionAggregator.<RunAsync>d__9.MoveNext() в /_/src/xunit.core/Sdk/ExceptionAggregator.cs:line 90

Почему это происходит? Пакет NuGet System.Reactive содержит специфическую информацию о целевом использовании для netstandard2.0 и других опций, и проекты .NET Framework 4.8 должны иметь возможность зависеть от библиотек .NET Standard 2.0, правильно?

“Недостающий” метод System.Reactive.Linq.ObservableEx.CombineLatest() легко найти с помощью функции “Перейти к определению” в Visual Studio. Ошибка теста возникает во время выполнения, а не на этапе компиляции. Тестовый проект не напрямую ссылается на пакет NuGet System.Reactive, но нужная DLL, похоже, присутствует в папке bin\x64 тестового проекта.

Свойства DLL в выходной папке тестового проекта

Ответ или решение

Проблема, с которой вы столкнулись, связана с тем, как .NET Framework 4.8 обрабатывает сборки, которые нацелены на .NET Standard, и с тем, что версии библиотек, используемых в проекте, могут быть несовместимы. Давайте разберем вашу ситуацию более подробно и предложим решение.

Описание проблемы

Вы создаете метод расширения в библиотеке, которая изначально была нацелена на .NET Framework 4.8, и все работало хорошо. Однако когда вы решили изменить целевую платформу на .NET Standard 2.0, ваше тестирование на .NET Framework 4.8 дает исключение MissingMethodException. Это указывает на то, что метод CombineLatest не может быть найден в библиотеке System.Reactive.

Причины возникновения исключения

  1. Версии NuGet пакетов: Эта ошибка может возникнуть, если в вашем проекте используются разные версии пакетных библиотек. Например, если ваша библиотека на .NET Standard 2.0 использует System.Reactive версии 6.0.1, а ваш проект, который тестируется, ссылается на другую версию System.Reactive, это может привести к несовместимости методов.

  2. Отсутствие прямой зависимости: Вы упомянули, что проект тестирования не указывает напрямую на System.Reactive. Это может быть причиной проблемы, так как ваша тестовая библиотека не может точно разрешить все зависимости, необходимые для правильной работы метода CombineLatest.

  3. Загруженные зависимости: При запуске тестов конфигурация загрузки сборок может привести к тому, что .NET Framework будет загружать неправильные версии DLL.

Рекомендации по решению

  1. Добавьте явную зависимость: Убедитесь, что в вашем проекте тестирования вы добавили явную ссылку на тот же пакет System.Reactive с той же версией, которая используется в вашем проекте расширений. Откройте файл .csproj вашего проекта тестирования и добавьте:

    <PackageReference Include="System.Reactive" Version="6.0.1" />
  2. Проверьте наличие конфликта версий: Убедитесь, что в конечном проекте и в проекте тестирования не происходит конфликтов версии вспомогательных библиотек. Для этого можно воспользоваться командой dotnet list package для управления зависимостями и их версиями.

  3. Проверьте bin-папку: Убедитесь, что в папке bin вашего тестового проекта находятся правильные версии всех необходимых сборок. Возможно, придется очистить проект (Clean) и выполнить повторную сборку (Rebuild).

  4. Обновите зависимости: Убедитесь, что все связанные пакеты находятся на актуальных версиях. Обновите их до последних стабильных версий, совместимых с вашими целями.

  5. Используйте .NET SDK: Убедитесь, что вы используете актуальные версии .NET SDK и инструменты для сборки, так как иногда более старые версии могут вызывать проблемы с совместимостью.

Заключение

Сложности виникают из-за несовместимости и проблем с зависимостями между библиотеками .NET Standard и .NET Framework. Следуя приведенным рекомендациям, вы сможете устранить данную проблему, связав все зависимости и убедившись, что ваше окружение полностью обновлено.

Оцените материал
Добавить комментарий

Капча загружается...