Переносимая библиотека с Xamarin - .NET Standard против UWP

У меня такая ситуация:

  • Assembly X - это создаваемая мной библиотека классов Xamarin. Он ориентирован на iOS, Android и .NET Standard 2.0.
  • Сборка X ссылается на API переносимости в Xamarin.Essentials.
  • Xamarin.Essentials ориентирован на iOS, Android, .NET Standard и UWP (uap10.0.16299).
  • Теперь кто-то хочет создать приложение для Windows 10 с помощью Assembly X.
  • Поскольку они в Windows 10, я бы хотел, чтобы они получили версию Xamarin.Essentials для UWP. Но мне кажется, что вместо этого он всегда использует версию .NET Standard, предположительно потому, что это то, что использует X. В результате они не получают специфичного для Windows поведения, которое может обеспечить Xamarin.Essentials.

Есть ли способ обойти это? Или мне также нужно создать версию X для UWP? Причина, по которой я избегал этого до сих пор, заключается в том, что тогда у меня будут одни цели, которые я могу построить только в Windows, а другие - только на Mac.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
107
1

Ответы 1

Дело не в том, что вам нужно строить вашей пользовательской сборки .NetStd каким-либо образом, зависящим от платформы. Вы компилируете против эталонную сборку Xamarin.Essentials .NetStd, а затем связать / включить специфичную для платформы сборку Xamarin.Essentials, которая включает код, зависящий от платформы.

Таким образом, в время выполнения типы в вашей пользовательской сборке .NetStd будут перенаправлены / вызваны в сборку, специфичную для платформы Xamarin.Essentials, которая была включена в ваше приложение.

Итак, в вашей пользовательской сборке .NetStd, которая включает Xamarin.Essentials, будет определение внешней сборки:

.assembly extern Xamarin.Essentials
{
  .ver 1:0:0:0
}

И затем в той же сборке .NetStd будет ваш код, который вызывает тип, который существует в сборке, то есть: OpenAppPackageFileAsync

IL_0030:  call [System.Threading.Tasks]System.Threading.Tasks.Task`1<[System.IO]System.IO.Stream> [Xamarin.Essentials]Xamarin.Essentials.FileSystem::OpenAppPackageFileAsync(string)

Примечание. В случае Essentials он не использует DI / Interfaces для вызова кода, зависящего от платформы, метод OpenAppPackageFileAsync вызывает метод PlatformOpenAppPackageFileAsync, и именно этот метод будет включать код, зависящий от платформы, в каждую из его зависимых от платформы сборок. В методе эталонной сборки на основе .NetStd он выдает NotImplementedInReferenceAssemblyException, поскольку не существует общего / универсального кода платформы на основе .NetStd, который реализует загрузку файлов Android / iOS / UWP, связанных с приложением только для чтения, то есть:

.method private hidebysig static [System.Threading.Tasks]System.Threading.Tasks.Task`1<[System.IO]System.IO.Stream>
          PlatformOpenAppPackageFileAsync(string filename) cil managed
  {
    // Code size       6 (0x6)
    .maxstack  8
    IL_0000:  newobj     instance void Xamarin.Essentials.NotImplementedInReferenceAssemblyException::.ctor()
    IL_0005:  throw
  } // end of method FileSystem::PlatformOpenAppPackageFileAsync

Теперь, когда вы упаковываете / объединяете свое зависящее от платформы приложение, скажем Android в этом примере, вы будете обрабатывать / включать не эталонную сборку Essentials, а версию для конкретной платформы.

Версия сборки Xamarin.Essentials.dll для Android включает это для метода PlatformOpenAppPackageFileAsync:

.method private hidebysig static [mscorlib]System.Threading.Tasks.Task`1<[mscorlib]System.IO.Stream>
          PlatformOpenAppPackageFileAsync(string filename) cil managed
  {
    // Code size       70 (0x46)
    .maxstack  3
    .locals init ([mscorlib]System.Threading.Tasks.Task`1<[mscorlib]System.IO.Stream> V_0,
             [Mono.Android]Java.IO.FileNotFoundException V_1)
    IL_0000:  ldarg.0
    IL_0001:  brtrue.s   IL_000e
    ~~~~
    .try
    {
      IL_001d:  call       [Mono.Android]Android.Content.Context Xamarin.Essentials.Platform::get_AppContext()
      IL_0022:  callvirt   instance [Mono.Android]Android.Content.Res.AssetManager [Mono.Android]Android.Content.Context::get_Assets()
      IL_0027:  ldarg.0
      IL_0028:  callvirt   instance [mscorlib]System.IO.Stream [Mono.Android]Android.Content.Res.AssetManager::Open(string)
      IL_002d:  call       [mscorlib]System.Threading.Tasks.Task`1<!!0> [mscorlib]System.Threading.Tasks.Task::FromResult<[mscorlib]System.IO.Stream>(!!0)
      IL_0032:  stloc.0
      IL_0033:  leave.s    IL_0044
      ~~~

Я не могу следить за байт-кодом в ваших примерах, но правильно ли я понимаю, что ответ в основном таков: явно включить Xamarin.Essentials в хост-приложение, а не просто полагаться на транзитивную зависимость от него из моей библиотеки классов?

E. Bishop 26.07.2018 03:36

@ E.Bishop Правильно, каждое хост-приложение должно включать / связывать "специальную" платформо-зависимую версию сборки, которая "соответствует" эталонной сборке (.assembly Name / Version / Types included / ...), которую вы скомпилировали библиотека .NetStd, которая содержит ваш пользовательский код для

SushiHangover 26.07.2018 03:42

К сожалению, насколько я могу судить, на практике это не работает. После добавления пакета Xamarin.Essentials непосредственно в мое хост-приложение кажется, что он все еще получает код .NET Standard от Xamarin.Essentials, когда он вызывается из библиотеки классов, о чем свидетельствует получение NotImplementedInReferenceAssemblyException.

E. Bishop 26.07.2018 19:44

@ E.Bishop Что такое платформа хост-приложения?

SushiHangover 26.07.2018 21:35

Ой, подождите ... Я думал, что это проект UWP, но на самом деле это был .NET 4.6. Я попробую еще раз с UWP.

E. Bishop 27.07.2018 01:59

Что ж, теперь я вижу другую проблему: это не позволяет мне вообще добавить мой пакет NuGet в проект UWP. Жалуется, что пакет несовместим с uap10.0.15063. Пакет имеет целевые значения netstandard1.4, netstandard1.6, netstandard2.0 и net45; Разве один из них не должен быть совместим с UWP?

E. Bishop 27.07.2018 02:02

@ E.Bishop UWP и NetStandard 2.0 в Windows 10 Fall Creators Update и более поздних версиях

SushiHangover 27.07.2018 02:21

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