Home > Blockchain >  MAUI: How to use partial classes for platform specific implementations together with net7.0 as Targe
MAUI: How to use partial classes for platform specific implementations together with net7.0 as Targe

Time:10-08

I am using partial classes to implement platform specific behavior in a .NET MAUI app:

Stem:

public partial class MyServices
{
    public partial void DoSomething();
}

Android/iOS/MacCatalyst/Windows/Tizen specific implementations all look similar to this:

public partial class MyServices
{
    public partial void DoSomething()
    {
        // Android/iOS/MacCatalyst/Windows/Tizen specific implementation
    }
}

So far, so normal for MAUI (although the platform specific implementation could be done differently, but the partial class approach is common for MAUI and seemed convenient).

Now, in order to be able to execute unit tests (xUnit), it is necessary to add the net7.0 target to the <TargetFrameworks> in the .csproj file of the SingleProject like this:

<PropertyGroup>
    <TargetFrameworks>net7.0;net7.0-android;net7.0-ios;net7.0-maccatalyst</TargetFrameworks>
    <TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net7.0-windows10.0.19041.0</TargetFrameworks>

    <!-- skipping irrelevant stuff here... -->

    <OutputType Condition="'$(TargetFramework)' != 'net7.0'">Exe</OutputType>
    
    <!-- skipping irrelevant stuff here... -->
</PropertyGroup>

This is just like Gerald Versluis describes in his YouTube video. The relevant code sample can be found here: https://github.com/jfversluis/MauixUnitTestSample/blob/main/MauixUnitTestSample/MauixUnitTestSample.csproj#L5

And this is where my problems start:

Due to the net7.0 target and a missing implementation of the MyServices class, I now receive this compiler error:

CS8795 Partial method 'MyServices.DoSomething()' must have an implementation part because it has accessibility modifiers.  MySampleApp (net7.0)

I haven't found any way to add a (dummy) implementation for the partial MyServices class to target net7.0 yet. However, I cannot remove the net7.0 target, because then I cannot run the unit tests anymore.

CodePudding user response:

Thanks to Gerald Versluis, I have figured it out based on the StatusBar implementation of the MAUI CommunityToolkit. So, here is my solution:

I changed to a slightly different approach. Instead of adding the partial classes to the Platform folders, I added a new folder and namespace and went with filename based multi-targeting as described here: https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/configure-multi-targeting#configure-filename-based-multi-targeting

My implementation files are now all in the same folder:

Services/Platform/
    MyServices.shared.cs
    MyServices.android.cs
    MyServices.ios.cs
    MyServices.windows.cs
    MyServices.net.cs

The MyServices.shared.cs file contains the method declaration whereas the platform-specific implementations reside in the platform-specific files.

In the .csproj I added the following inside the <Project> node:

 <!-- Android -->
  <ItemGroup Condition="$(TargetFramework.StartsWith('net7.0-android')) != true">
    <Compile Remove="**\**\*.Android.cs" />
    <None Include="**\**\*.Android.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
  </ItemGroup>

  <!-- iOS -->
  <ItemGroup Condition="$(TargetFramework.StartsWith('net7.0-ios')) != true">
    <Compile Remove="**\**\*.iOS.cs" />
    <None Include="**\**\*.iOS.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
  </ItemGroup>

  <!-- Mac Catalyst -->
  <ItemGroup Condition="$(TargetFramework.StartsWith('net7.0-maccatalyst')) != true">
    <Compile Remove="**\**\*.MacCatalyst.cs" />
    <None Include="**\**\*.MacCatalyst.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
  </ItemGroup>

  <!-- Windows -->
  <ItemGroup Condition="$(TargetFramework.StartsWith('net7.0-windows')) != true">
    <Compile Remove="**\*.Windows.cs" />
    <None Include="**\*.Windows.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
  </ItemGroup>

  <!-- .NET -->
  <ItemGroup Condition="!($(TargetFramework.StartsWith('net')) == true AND $(TargetFramework.EndsWith('.0')) == true AND $(TargetFramework.Contains('-')) != true)">
    <!-- e.g net6.0 or net7.0 -->
    <Compile Remove="**\*.net.cs" />
    <None Include="**\*.net.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
  </ItemGroup>

It works like a charm and I can run unit tests, too. Perfect setup.

  • Related