プラットフォーム依存の参照を使用して、WindowsおよびMac用の.Netライブラリを作成する方法はありますか?


12

C#を使用して、デスクトップ(WindowsおよびMac)用のクロスプラットフォームアプリを開発しようとしています。このアプリにはプラットフォームに依存するものが大量に含まれており、チームリーダーはそのコードをすべてC#で記述することを望んでいます。これを行う簡単な方法は、C ++でラッパーを作成し、C#コードでライブラリを参照するだけで、C ++ライブラリがプラットフォームの問題を処理できるようにすることです。

Visual Studio for Macを使用してライブラリをセットアップしようとしています。単一のライブラリに単一のインターフェイスを提供して、現在のプラットフォームの音声ライブラリへのネイティブテキストへのアクセスを許可することを望んでいます。できれば2つのアセンブリを作成する必要はありません。C#for Windowsのテキスト読み上げライブラリはMacでは利用できないため、ブリッジを提供する以外の選択肢はありません。

ライブラリでオペレーティングシステムのルックアップを実行して、どのオペレーティングシステムで実行されているかを判断したり、ネイティブライブラリのロードを試みたり、ロードするライブラリを使用したりすることに満足しています。

必要に応じて、2つの実装を記述できる単一のプロジェクトを作成する必要があります。Visual Studio for Macでライブラリプロジェクトを作成する方法を見つけられませんでしたが、作成できるようになります。複数の実装を許可するプロジェクトの唯一のタイプは、実装がiOSまたはAndroidのいずれかであることを必要とするようです。


どの.NETランタイムを使用しますか?
陶酔

2
Xamarinも同様のことを行います。たぶんビルド構成で?
ユアン

2
Visual Studio for Macは実際にはビジュアルスタジオではないことに注意してください。Xamarinのドキュメントに何かありますか?
richzilla

3
最適なアプローチは、さまざまなアセンブリになります... 1つはインターフェイスと共通コード用で、もう1つはターゲットプラットフォーム用です。ただし、複数のターゲットを設定し、#ifステートメントを使用して実装を交換できます。欠点は、有効になっていないものは評価されないため、簡単に期限切れになる可能性があることです。
ベリンロリチュ

プラットフォーム依存の参照を言うとき、ネイティブコードを話しているのですか、それともすべてC#コードを話しているのですか?
ベリンロリチュ

回答:


4

いい質問があります。ソリューションには、おそらくいくつかのトレードオフがあります。最終的な答えは、プラットフォームに依存するという意味によって異なります。たとえば、外部アプリケーションを起動するプロセスを起動していて、アプリケーション間を切り替えるだけの場合、おそらくそれほど複雑にすることなく処理できます。ネイティブライブラリとP / Invokeを話している場合は、もう少しやらなければならないことがあります。ただし、1つのプラットフォームにのみ存在するライブラリとリンクする場合は、おそらく複数のアセンブリを使用する必要があります。

外部アプリ

#ifこの状況では、おそらくステートメントを使用する必要はないでしょう。いくつかのインターフェースを設定するだけで、プラットフォームごとに1つの実装があります。ファクトリを使用してプラットフォームを検出し、適切なインスタンスを提供します。

場合によっては、特定のプラットフォーム用にコンパイルされた単なるバイナリですが、実行可能ファイルの名前とすべてのパラメーターは同じように定義されています。その場合、適切な実行可能ファイルを解決する必要があります。WindowsとLinuxで実行できるバルクオーディオコンバーターアプリの場合、バイナリ名を解決する静的イニシャライザーを使用しました。

public class AudioProcessor
{
    private static readonly string AppName = "lame";
    private static readonly string FullAppPath;

    static AudioProcessor()
    {
        var platform = DetectPlatform();
        var architecture = Detect64or32Bits();

        FullAppPath = Path.combine(platform, architecture, AppName);
    }
}

ここには何も派手なものはありません。昔ながらのクラス。

P / Invoke

P / Invokeは少し複雑です。一番下の行は、ネイティブライブラリの正しいバージョンがロードされていることを確認する必要があるということです。WindowsではP / Invokeを実行しSetDllDirectory()ます。異なるプラットフォームでは、その手順は必要ない場合があります。だから、物事が乱雑になる場所です。あなたは使用する必要があり#if、あなたの配布パッケージに含めている場合は特に-コールが自分のライブラリーのパスを解決し制御するために使用されるコントロールへのステートメントを。

完全に異なるプラットフォーム依存ライブラリへのリンク

ここでは、旧式のマルチターゲティングアプローチが役立つ場合があります。しかし、それは多くのugさを伴います。一部のプロジェクトが同じDLLをSilverlight、WPF、および潜在的にUAPをターゲットにしようとする時代には、異なるコンパイルタグでアプリケーションを複数回コンパイルする必要がありました。上記の各プラットフォームの課題は、同じ概念を共有しているにもかかわらず、プラットフォームが十分に異なるため、それらの違いを回避する必要があることです。これは私たちが地獄に入る場所です#if

このアプローチでは、.csprojプラットフォーム依存の参照を処理するためにファイルを手動で編集する必要もあります。あなた以来.csprojファイルがMSBuildのファイルがあり、それが知られており、予測可能な方法で行うことが完全に可能です。

#地獄の場合

#ifステートメントを使用してコードのセクションをオンまたはオフにできるため、アプリケーション間のわずかな違いを効果的に処理できます。表面的には、良いアイデアのように聞こえます。境界ボックスの視覚化をオンまたはオフにして、描画コードをデバッグする手段としても使用しました。

番号1の問題は、#ifということであるどれもオフになっているコードがパーサーによって評価されていません。潜在的な構文エラー、またはさらに悪いことに、ライブラリの再コンパイルを待機する論理エラーが発生する場合があります。これは、コードのリファクタリングでさらに問題になります。メソッドの名前を変更したり、パラメーターの順序を変更したりするような単純なものは通常は正常に処理されますが、パーサーは#ifステートメントによってオフにされたものを評価しないため、再コンパイルするまで表示されないコードが突然壊れます。

その方法で書かれた私のデバッグコードはすべて、一連のリファクタリングが壊れた後に書き直さなければなりませんでした。書き換え中に、グローバル構成クラスを使用してこれらの機能をオンまたはオフにしました。これにより、ツールのリファクタリングが可能になりましたが、APIが完全に異なる場合、このようなソリューションは役に立ちません。

私の好きな方法

学んだ多くの苦痛な教訓に基づいて、そしてマイクロソフト自身の例に基づいた私の好ましい方法は、複数のアセンブリを使用することです。

1つのコアNetStandardアセンブリは、すべてのインターフェイスを定義し、すべての共通コードを含みます。プラットフォーム依存の実装は、含まれる場合に機能を追加する別のアセンブリになります。

このアプローチは、新しい構成APIと現在のIDアーキテクチャによって実証されています。より具体的な統合が必要な場合は、それらの新しいアセンブリを追加するだけです。これらのアセンブリは、セットアップに自分自身を組み込むための拡張機能も提供します。依存性注入アプローチを使用している場合、これらの拡張メソッドにより、ライブラリはそのサービスを登録できます。

これは、#if地獄を避け、実質的に異なる環境を満たすために私が知っている唯一の方法です。


私はC#を嫌います(C ++を約18年間、C#を約半日使用しているのは当然です)。この新しい構成API ...にいくつかのリンクを提供できます。私は自分でそれを見つけることができないようです。
クリア

2
docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/… 構成ソースを追加するための複数のNugetパッケージがあります。たとえば、環境変数、JSONファイルなどから
Berin Loritsch

1
Microsoft.Extensions.ConfigurationAPI のセットです。
ベリンロリチュ

1
ルートgithubプロジェクトは次のとおり
Berin Loritsch
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.