質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
.NET Standard

.NET Standardは、さまざまな.NET環境で用いることができる基本的なAPIセットまたはそれを定めた仕様です。この標準に沿って.NET実装を行うことで、どのプラットフォームでも動くポータブルなライブラリを作成できます。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Q&A

解決済

1回答

16124閲覧

.NET Standard クラスライブラリを参照すると出力フォルダに.dllが大量に出力される理由

g_uo

総合スコア212

.NET Standard

.NET Standardは、さまざまな.NET環境で用いることができる基本的なAPIセットまたはそれを定めた仕様です。この標準に沿って.NET実装を行うことで、どのプラットフォームでも動くポータブルなライブラリを作成できます。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

0グッド

1クリップ

投稿2018/08/31 02:18

質問

.NET Standard クラスライブラリを .NET Framework のプロジェクトで参照したとき、.NET Framework の出力先フォルダにDLLが大量に出力されます。
このようにたくさんのDLLが出力される理由をご教示いただきたいです。
また、もしこのようなDLL出力をやめる方法があれば合わせてご教示いただければ幸いでございます。

出力フォルダ

環境情報

OS: Windows 10 Pro 64bit (1803)
IDE: Visual Studio Community 2017 (v15.8.1)
.NET Framework: 4.6.1
.NET Standard: 2.0
言語: C#

[サンプルプロジェクト情報]
HelloStandard : クラスライブラリ (.NET Standard)
HogeConsole: コンソールアプリ (.NET Framework)

私見

認識の間違いは是非ご指摘頂戴したいのですが、
私の考えとしては、netstandard.dllのもつ依存関係が原因かな、と思っております。
ただ、.NET Standard 2.0 は .NET Framework 4.6.1 をサポートしており、Frameworkだけがもつ部分は別として、Standard と Framework で異なる依存関係をもつということがしっくりきません。
(しかしながら、そもそも理解不足もあると思います)

質問の背景

実行ファイルを配布する際、何らかの不手際でDLLのコピー漏れが発生するリスクが高く、依存関係のあるファイルは少なくしたいという思いがあり、質問いたしました。
自動化すれば問題ないか...とも思いましたが、その自動化スクリプトのチェック自体が煩雑になることと、今後リリースの度、たくさんのDLL(もちろん改造に伴って追加されるDLLも)に漏れがないかどうか確認するのは骨が折れると思っています。

.NET Standardのクラスライブラリを作成しようと思った理由としては、時代の流れというのが一番の理由ですが、既存資産を.NET Standardクラスライブラリに移行し、Windows以外のプラットフォームにも展開可能な状態にしておきたいという判断からです。

サンプルプロジェクトのソースコード

プロジェクト: HelloStandard

HelloStandard.cs

csharp

1using System; 2 3namespace Standard 4{ 5 public class HelloStandard 6 { 7 public HelloStandard(string message) 8 { 9 Message = message; 10 } 11 12 public string Message { get; } 13 14 public void PrintOut() 15 { 16 Console.WriteLine(Message); 17 } 18 } 19}

HelloStandard.csproj

xml

1<Project Sdk="Microsoft.NET.Sdk"> 2 3 <PropertyGroup> 4 <TargetFramework>netstandard2.0</TargetFramework> 5 <RootNamespace>Standard</RootNamespace> 6 </PropertyGroup> 7 8</Project>

プロジェクト: HogeConsole

Program.cs

csharp

1using Standard; 2 3namespace HogeConsole 4{ 5 internal class Program 6 { 7 private static void Main(string[] args) 8 { 9 var helloStandard = new HelloStandard("Hello .NET Standard!!"); 10 helloStandard.PrintOut(); 11 } 12 } 13}
Hello .NET Standard!!

App.config

xml

1<?xml version="1.0" encoding="utf-8" ?> 2<configuration> 3 <startup> 4 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /> 5 </startup> 6</configuration>

HogeConsole.csproj

xml

1<?xml version="1.0" encoding="utf-8"?> 2<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 3 <Import Project="$(MSBuildExtensionsPath)$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)$(MSBuildToolsVersion)\Microsoft.Common.props')" /> 4 <PropertyGroup> 5 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> 6 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> 7 <ProjectGuid></ProjectGuid> 8 <OutputType>Exe</OutputType> 9 <RootNamespace>HogeConsole</RootNamespace> 10 <AssemblyName>HogeConsole</AssemblyName> 11 <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> 12 <FileAlignment>512</FileAlignment> 13 <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> 14 <Deterministic>true</Deterministic> 15 </PropertyGroup> 16 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> 17 <PlatformTarget>AnyCPU</PlatformTarget> 18 <DebugSymbols>true</DebugSymbols> 19 <DebugType>full</DebugType> 20 <Optimize>false</Optimize> 21 <OutputPath>bin\Debug\</OutputPath> 22 <DefineConstants>DEBUG;TRACE</DefineConstants> 23 <ErrorReport>prompt</ErrorReport> 24 <WarningLevel>4</WarningLevel> 25 </PropertyGroup> 26 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> 27 <PlatformTarget>AnyCPU</PlatformTarget> 28 <DebugType>pdbonly</DebugType> 29 <Optimize>true</Optimize> 30 <OutputPath>bin\Release\</OutputPath> 31 <DefineConstants>TRACE</DefineConstants> 32 <ErrorReport>prompt</ErrorReport> 33 <WarningLevel>4</WarningLevel> 34 </PropertyGroup> 35 <ItemGroup> 36 <Reference Include="System" /> 37 <Reference Include="System.Core" /> 38 <Reference Include="System.Xml.Linq" /> 39 <Reference Include="System.Data.DataSetExtensions" /> 40 <Reference Include="Microsoft.CSharp" /> 41 <Reference Include="System.Data" /> 42 <Reference Include="System.Net.Http" /> 43 <Reference Include="System.Xml" /> 44 </ItemGroup> 45 <ItemGroup> 46 <Compile Include="Program.cs" /> 47 <Compile Include="Properties\AssemblyInfo.cs" /> 48 </ItemGroup> 49 <ItemGroup> 50 <None Include="App.config" /> 51 </ItemGroup> 52 <ItemGroup> 53 <ProjectReference Include="..\HelloStandard\HelloStandard.csproj"> 54 <Project></Project> 55 <Name>HelloStandard</Name> 56 </ProjectReference> 57 </ItemGroup> 58 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> 59</Project>

以上です。どうぞよろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんにちは。

ご存じの通り、NETStandardには「実装がありません」。あるのは「大量のクラスとメソッドシグネチャによるAPI定義」だけです。具体的には、「中身(実装)が空っぽのクラス定義だけを詰めたアセンブリ」の集まりで構成されています。
どうしてそんなことになっているかというと、NETStandardは最初からクロスプラットフォームライブラリを作成するために設計されたもので、「各プラットフォームのAPIへの直接アクセス」ではなく、「薄いアセンブリを介した呼び出し」とすることで実装の差し替えを可能としているのです。C#で言う、オブジェクトの直接使用を避けてインターフェースを一枚挟んでいるような状態をイメージすれば良いです。そして、そのインターフェース群こそが、画像にある大量のDLLファイルの正体です。

おそらくですが、それらのDLLのうち、netstandard.dllが追加したアセンブリをごっそり削除してもアプリは動くんじゃないかなーと思います。ランタイムが.NET Frameworkであるなら、参照アセンブリを外しても.NET Framework側の実装アセンブリを直接参照することになるはずです。(たぶん!)


と言っても、そんなこわいことできないので、ここは別の視点から、

「Visual Studioのpublish機能を使ってリリースを作成する」

というのをオススメしてみます。
publishは通常のビルドと違って、アプリに必要なアセンブリやデータ類を一カ所にまとめて出力するもので、これをそのままpackして配布や更新に利用するのが最も安全かつ確実な手段となります。
.NET Core SDKを利用していてdotnetコマンドが使用可能な状態であれば、dotnet publishコマンドで同様のことを行うこともできるので、スクリプト化も十分可能です。


もう一つの提案としては、

「NETStandardのライブラリをnet461とマルチターゲットにする」

という方法があります。
これは、ライブラリをNETStandardとの互換性を保ったまま、.NET Frameworkに対してはnet461のアセンブリが提供されるようにできるため、netのアプリに対してNETStandardのインターフェース参照がごっそり追加されるということ自体を回避できます。
こちらの方法を採用する場合、ライブラリの「開発環境」が.NET Frameworkに対応している必要があります。NETStandardシングルであればLinux上でも開発可能ですが、netとクロスにするとWindowsでしかビルドできなくなります。


どちらの方法が優れているということもないですが、個人的には、プロジェクトは変更せず、発行プロセスを工夫する方が、選べるならその方が懸念点が少なくて良いですね。
もし、マルチターゲットを選んだとしても、配布に向けたビルドプロセスを見直すことは考えてみても良いのではないかと思います。

投稿2018/08/31 12:43

tamoto

総合スコア4103

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

g_uo

2018/09/03 02:09

tamotoさん、未だ情報少ない中、貴重な回答ありがとうございます。 まず、私のNET Standardに関する知識が不足しておりました。ご教示いただいた、インターフェース群という考え方でDLL大量出力の疑問も解決しましたし、そう考えれば自然なことと理解できました。 また、ご提案いただいた2つ方法について当方の環境で実際試してみました。 結果、マルチターゲットのほうで出力DLLをなくすことができましたが、プロジェクトファイルに記載するReferenceタグで混乱しそうなことと、自分以外が作ったライブラリの依存関係まで正確に把握しきれない可能性もあると思いました。なのでpublishを用いてpackするほうが、ファイル数は増えども結果的に安全な方法であるという考えに至りました。 よって、今後publishを基本にして、安全かつ手数の少ない方法を模索してみます。 また機会がございましたらご助力いただければ幸いでございます。 余談ですが、tamotoさんがteratailの.NET Standardタグ初めての回答者さんです! ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問