Вопрос или проблема
У меня есть метод расширения, определенный в библиотеке классов (назовем ее 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
тестового проекта.
Ответ или решение
Проблема, с которой вы столкнулись, связана с тем, как .NET Framework 4.8 обрабатывает сборки, которые нацелены на .NET Standard, и с тем, что версии библиотек, используемых в проекте, могут быть несовместимы. Давайте разберем вашу ситуацию более подробно и предложим решение.
Описание проблемы
Вы создаете метод расширения в библиотеке, которая изначально была нацелена на .NET Framework 4.8, и все работало хорошо. Однако когда вы решили изменить целевую платформу на .NET Standard 2.0, ваше тестирование на .NET Framework 4.8 дает исключение MissingMethodException
. Это указывает на то, что метод CombineLatest
не может быть найден в библиотеке System.Reactive
.
Причины возникновения исключения
-
Версии NuGet пакетов: Эта ошибка может возникнуть, если в вашем проекте используются разные версии пакетных библиотек. Например, если ваша библиотека на .NET Standard 2.0 использует
System.Reactive
версии 6.0.1, а ваш проект, который тестируется, ссылается на другую версиюSystem.Reactive
, это может привести к несовместимости методов. -
Отсутствие прямой зависимости: Вы упомянули, что проект тестирования не указывает напрямую на
System.Reactive
. Это может быть причиной проблемы, так как ваша тестовая библиотека не может точно разрешить все зависимости, необходимые для правильной работы методаCombineLatest
. -
Загруженные зависимости: При запуске тестов конфигурация загрузки сборок может привести к тому, что .NET Framework будет загружать неправильные версии DLL.
Рекомендации по решению
-
Добавьте явную зависимость: Убедитесь, что в вашем проекте тестирования вы добавили явную ссылку на тот же пакет
System.Reactive
с той же версией, которая используется в вашем проекте расширений. Откройте файл.csproj
вашего проекта тестирования и добавьте:<PackageReference Include="System.Reactive" Version="6.0.1" />
-
Проверьте наличие конфликта версий: Убедитесь, что в конечном проекте и в проекте тестирования не происходит конфликтов версии вспомогательных библиотек. Для этого можно воспользоваться командой
dotnet list package
для управления зависимостями и их версиями. -
Проверьте bin-папку: Убедитесь, что в папке
bin
вашего тестового проекта находятся правильные версии всех необходимых сборок. Возможно, придется очистить проект (Clean
) и выполнить повторную сборку (Rebuild
). -
Обновите зависимости: Убедитесь, что все связанные пакеты находятся на актуальных версиях. Обновите их до последних стабильных версий, совместимых с вашими целями.
-
Используйте .NET SDK: Убедитесь, что вы используете актуальные версии .NET SDK и инструменты для сборки, так как иногда более старые версии могут вызывать проблемы с совместимостью.
Заключение
Сложности виникают из-за несовместимости и проблем с зависимостями между библиотеками .NET Standard и .NET Framework. Следуя приведенным рекомендациям, вы сможете устранить данную проблему, связав все зависимости и убедившись, что ваше окружение полностью обновлено.