C
C#•2mo ago
revolt

Partial classes and platform specific code

Hello. Trying to create platform specific code and only use/compile the code for correct platform upon release. My current issue is that regardless of platform my linux specific code is trying to run on windows. I seen examples of it using MAUI, however i'm just trying to make a simple console app. In my csproj:
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Windows'))">
<DefineConstants>WINDOWS</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Linux'))">
<DefineConstants>LINUX</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Windows'))">
<DefineConstants>WINDOWS</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Linux'))">
<DefineConstants>LINUX</DefineConstants>
</PropertyGroup>
Base class:
public partial class Platform
{
public partial void SetWallpaper(string path);
}
public partial class Platform
{
public partial void SetWallpaper(string path);
}
used like this:
#if WINDOWS
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32;

public partial class Platform
{
public partial void SetWallpaper(string path)
{
//implementation
}
}
#endif
#if WINDOWS
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32;

public partial class Platform
{
public partial void SetWallpaper(string path)
{
//implementation
}
}
#endif
an identical implementation is done for linux and all code is in the same namespace and it's built using this command: dotnet publish wallpaper.csproj -r win-x64 -c Release
20 Replies
revolt
revolt•2mo ago
Thought partials would be a good use case for this, but cmiiw and if a easier way exists
canton7
canton7•2mo ago
https://learn.microsoft.com/en-us/visualstudio/msbuild/property-functions?view=vs-2022#msbuild-property-functions:
Specify whether the current OS platform is platformString. platformString must be a member of OSPlatform.
https://stackoverflow.com/a/65289488/1086121 suggests the thing to do is to check on $(RuntimeIdentifier)? Not sure whether there's anything more specific Also https://github.com/dotnet/msbuild/issues/5065#issuecomment-2271062217
revolt
revolt•2mo ago
Thanks for the help. Just checked out that github and tried the below and it now works on windows but not linux. Gonna look at some more stuff now that you linked
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith('linux'))">
<DefineConstants>$(DefineConstants);LINUX</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith('win'))">
<DefineConstants>$(DefineConstants);WINDOWS</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith('linux'))">
<DefineConstants>$(DefineConstants);LINUX</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith('win'))">
<DefineConstants>$(DefineConstants);WINDOWS</DefineConstants>
</PropertyGroup>
sorry to expand on it I now get the below error: Partial method 'Platform.SetWallpaper(string)' must have an implementation part because it has accessibility modifiers.
canton7
canton7•2mo ago
Yepyep. Remember that not-implemented partial methods are removed from the caller. That can only happen if the caller is in the same class
revolt
revolt•2mo ago
Hmm. So would that mean that the condition is not met in csproj, therefore the compiler removes the code (implementations) specified using #if? (Expected if csproj is wrong) Or is it now correct and that my actual code is wrong.
canton7
canton7•2mo ago
If you have a partial method without a body, it must have 0 access modifiers So your code is wrong
revolt
revolt•2mo ago
Just looking at this article it seems like its okay to define it with access modifier? Sorry still learning https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/invoke-platform-code?view=net-maui-8.0
.NET MAUI invoking platform code - .NET MAUI
Learn how to invoke platform code in a .NET MAUI app by using conditional compilation, or by using partial classes and partial methods.
canton7
canton7•2mo ago
Ah, maybe I'm wrong
revolt
revolt•2mo ago
ur good. I think it points back to the csproj being wrong again, but im not sure.
arion
arion•2mo ago
The difference between setting it in the .csproj and setting checking it at runtime is 1 has runtime overhead (though minimal) and the other doesnt. You could when publishing for Linux or Windows include the constant in there if you want dotnet publish -p:DefineConstants="LINUX" --os linux Additionally for code like the platform code you specified, you could create a similar interface then declare a platform specific implementation of that eg.
public interface IWallpaperSetter // idk of a better name lol, u got just 1 method
{
public void SetWallpaper(string path);
}
public interface IWallpaperSetter // idk of a better name lol, u got just 1 method
{
public void SetWallpaper(string path);
}
then you can write up an implementation for each platform like
public class LinuxWallpaperSetter : IWallpaperSetter
{
public void SetWallpaper(string path)
{
// Linux specific code
}
}

// ---
public class WindowsWallpaperSetter : IWallpaperSetter
{
public void SetWallpaper(string path)
{
// Windows specific code
}
}
public class LinuxWallpaperSetter : IWallpaperSetter
{
public void SetWallpaper(string path)
{
// Linux specific code
}
}

// ---
public class WindowsWallpaperSetter : IWallpaperSetter
{
public void SetWallpaper(string path)
{
// Windows specific code
}
}
For checking at runtime, you could do
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
}
or
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
}
revolt
revolt•2mo ago
Thanks for the example code. I ended up doing it at runtime pretty much how you showed here. My only question is that do u think originally that publishing it using the args you provided would have worked? I'd go back and try but didnt use git
arion
arion•2mo ago
No description
No description
arion
arion•2mo ago
If neither constant is provided, it will just write out Hello,
Unknown User
Unknown User•2mo ago
Message Not Public
Sign In & Join Server To View
revolt
revolt•2mo ago
If you can provide an example that would be great, just looking at it seems too complicated for this use case I was mainly talking about in my specific example with partial classes, thank you for the test though 🙂
Unknown User
Unknown User•2mo ago
Message Not Public
Sign In & Join Server To View
revolt
revolt•2mo ago
will take a look, thanks so i took a quick look and this only seems to apply to ide/dev ux and warnings and does not affect compilation
Unknown User
Unknown User•2mo ago
Message Not Public
Sign In & Join Server To View
revolt
revolt•2mo ago
You are right I should use one of attributes provided, but I believe that is a seperate issue to my original problem. In regards to the bad msbuild, are you saying that it takes the host OS when building and not the target os? So instead of using IsOSPlatform I would use something like Condition="$(RuntimeIdentifier.StartsWith('win'))" instead, like a commenter above pointed out. However this just brings me back to the error of "Partial method 'Platform.SetWallpaper(string)' must have an implementation part because it has accessibility modifiers." correct? My goal was to use partial classes and conditional compilation similair to maui example. I do appreciate everyones help though 🙂 And yes just for something simple I think we have established that conditional calling based on platform is probably the best bet, but I would still like to see why this wasn't working for me.
Unknown User
Unknown User•2mo ago
Message Not Public
Sign In & Join Server To View
Want results from more Discord servers?
Add your server