0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[C#]プリプロセッサと.csprojでクロスプラットフォームにする

Posted at

課題

今までファイル選択やらちょっとしたダイアログにWindows Formsを使っていましたが、それだと今持っているMacBookで実行できないことに気づきました。それだと外で気軽に編集できないし、何よりWindowsだけに向けたアプリになってしまうのでそのアプリを使ってくれる人が少しだけ減ってしまうことになります。

解決策と問題点

自分はファイル選択や、ちょっとメッセージを表示するくらいにしかWindows Formsを使っていなかったので、普通にコンソールで代用できるかなと思いました。まぁ頑張ればそのOS用のUIを使えたかもしれませんが
そこで、#ifを使ってWindowsの時はWindows Formsを使って、それ以外はコンソールにするみたいな感じにしようと思いましたが、#ifで使う用の_WINDOWS_みたいにOSごとに定義されるやつがなかったんです。つまり、コンパイル時にOSごとにコードを分けることができなくて、Windows Formsが使われてるコードをコンパイルするときにエラーが出るんです。
ちょっと調べてみると、.csprojの<PropertyGroup Condition="XXX">のように、XXXのところに条件を入れてOSごとに定義できることが分かりました。

Project.csproj
...
  <PropertyGroup Condition="$([System.OperatingSystem]::IsWindows())">
    <DefineConstants>_WINDOWS_</DefineConstants>
  </PropertyGroup>

  <PropertyGroup Condition="$([System.OperatingSystem]::IsMacOS())">
    <DefineConstants>_MACOS_</DefineConstants>
  </PropertyGroup>

  <PropertyGroup Condition="$([System.OperatingSystem]::IsLinux())">
    <DefineConstants>_LINUX_</DefineConstants>
  </PropertyGroup>
...

こうすることで、Windowsなら_WINDOWS_、MacOSなら_MACOS_のように、OSごとに定義することができます。
やっとできたのでビルドしてみると、.csprojでWindows Formが有効になってるとかターゲットフレームワークが.net6.0-windowsになってるとかで(正確なエラーは覚えていませんが)エラーが出ました。
そこで.csprojの上の方を見てみると、<UseWindowsForms>true</UseWindowsForms>とかいういかにもWindows Formsを使うって宣言してる行と、<TargetFramework>net6.0-windows</TargetFramework>がありました。

Project.csproj
...
  <PropertyGroup>
    <TargetFramework>net6.0-windows</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
  </PropertyGroup>
...

OSごとにフレームワークを変えるってできるのか?って思いましたが、そういえばさっき<PropertyGroup>を使っていました。
解決策として、普通にさっきのOSごとの<PropertyGroup>に移しました。

Project.csproj
...
   <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
-    <TargetFramework>net6.0-windows</TargetFramework>
-    <UseWindowsForms>true</UseWindowsForms>
   </PropertyGroup>
 
   <PropertyGroup Condition="$([System.OperatingSystem]::IsWindows())">
     <DefineConstants>_WINDOWS_</DefineConstants>
+    <TargetFramework>net6.0-windows</TargetFramework>
+    <UseWindowsForms>true</UseWindowsForms>
   </PropertyGroup>
 
   <PropertyGroup Condition="$([System.OperatingSystem]::IsMacOS())">
     <DefineConstants>_MACOS_</DefineConstants>
   </PropertyGroup>
 
   <PropertyGroup Condition="$([System.OperatingSystem]::IsLinux())">
     <DefineConstants>_LINUX_</DefineConstants>
   </PropertyGroup>
...

まとめ

.csprojをこういう風に変更する

Project.csproj
...
   <PropertyGroup>
+    <TargetFramework>netX.X</TargetFramework>
-    <TargetFramework>netX.X-windows</TargetFramework>
-    <UseWindowsForms>true</UseWindowsForms>
   </PropertyGroup>
 
   <PropertyGroup Condition="$([System.OperatingSystem]::IsWindows())">
     <DefineConstants>_WINDOWS_</DefineConstants>
+    <TargetFramework>netX.X-windows</TargetFramework>
+    <UseWindowsForms>true</UseWindowsForms>
   </PropertyGroup>
 
   <PropertyGroup Condition="$([System.OperatingSystem]::IsMacOS())">
     <DefineConstants>_MACOS_</DefineConstants>
   </PropertyGroup>
 
   <PropertyGroup Condition="$([System.OperatingSystem]::IsLinux())">
     <DefineConstants>_LINUX_</DefineConstants>
   </PropertyGroup>
...

コピペしてもいいですが、もともとある<UseWindowsForms><TargetFramework>は消して、netX.Xをちゃんとしたバージョンに変えてください。

コードで使う例:

example.cs
using System;

public IDialog CreateDialog(string message)
{
#if _WINDOWS_
    return new WindowsDialog(message) //Windowsでのみ実行される
#elif _MACOS_
    return new MacOSDialog(message)
#elif _LINUX_
    return new LinuxDialog(message)
#else
    throw new PlatformNotSupportedException(); //Windows,MacOS,Linuxのどれでもない場合にエラー
#endif
}

こんな感じで、OSごとのクラスと全体のインターフェースを作って、#ifで分岐させるようにすればいいと思います。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?