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

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

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

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

Visual Studio

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

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

2回答

2795閲覧

【C#】【.Net】Appクラスでコンポーネントクラスの開放すると警告番号CA1001が出る件を解決したい

hasshy

総合スコア102

C#

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

Visual Studio

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

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

0クリップ

投稿2020/06/16 18:07

編集2020/06/18 18:06

WPFで常駐アプリを開発しているのですが、解決方法が分からない警告があり質問させてください。

コポーネントクラスを使ったアプリケーションを作成しています。
App.xml.csの中でコンポーネントクラスを開放する処理を書いているのですが、下記に該当する警告が発生します。
CA1001:破棄可能なフィールドを所有する型は、破棄可能でなければなりません

そもそも、コンポーネントクラスの開放は不要でしょうか?
それとも、コンポーネントクラスの開放は必要で、
AppクラスをIDisposableインターフェイスとして実装して開放できるようにするのが一般的なのでしょうか?

コンポーネントクラスを使うプロジェクトの情報は見つかるのですが、該当の警告の対応方法や開放の方法が見つかりませんでした。
そのため、こちらで質問させていただきました。

参考にしたページ

C# WPF で タスクトレイ 常駐アプリ の 開発

参考にしたページではコンポーネントクラスの開放しています。

元のソース

プロジェクト内で、NotifyIconWrapperと言うコンポーネントクラスを作っています。
タスクメニューに表示するアイコンのラッパーです。

アプリケーションを終了する際にコンポーネントクラスを開放します。
開始時にインスタンスを作る処理を記載し忘れておりました。

cs

1namespace SampleProject 2{ 3 /// <summary> 4 /// App.xaml の相互作用ロジック 5 /// </summary> 6 public partial class App : Application, IDisposable 7 { 8 9 /// <summary> 10 /// タスクトレイに表示するアイコンのコンポーネント 11 /// </summary> 12 private NotifyIconWrapper NotifyIconWrapper = new NotifyIconWrapper(); 13 14 /// <summary> 15 /// System.Windows.Application.Exit イベントのラッパー 16 /// </summary> 17 /// <param name="e"></param> 18 protected override void OnExit(ExitEventArgs e) 19 { 20 base.OnExit(e); 21 this.NotifyIconWrapper.Dispose(); 22 } 23 } 24}

Visual Studioのログに表示されるエラー

CA1001: 型'App'は破棄可能なフィールド'notifyIcon'を所有しますが、破棄可能ではありません。

試した事

クイックアクションとリファクタリングを参考に、IDisposableインターフェイスを実装しました。

cs

1namespace SampleProject 2{ 3 /// <summary> 4 /// App.xaml の相互作用ロジック 5 /// </summary> 6 public partial class App : Application, IDisposable 7 { 8 9 /// <summary> 10 /// タスクトレイに表示するアイコンのコンポーネント 11 /// </summary> 12 private NotifyIconWrapper notifyIcon = new NotifyIconWrapper(); 13 14 public void Dispose() 15 { 16 throw new NotImplementedException(); 17 } 18 19 /// <summary> 20 /// System.Windows.Application.Exit イベントのラッパー 21 /// </summary> 22 /// <param name="e"></param> 23 protected override void OnExit(ExitEventArgs e) 24 { 25 base.OnExit(e); 26 this.notifyIcon.Dispose(); 27 } 28 } 29}

発生したエラー

実装したところ別の警告が発生して、Appクラスそのものを大きく修正しないと解決出来ないエラーが発生しました。

コード説明
CA1065Dispose は型 NotImplementedException の例外を作成します。この型のメソッドでは例外を発生させることはできません。この例外インスタンスが発生する可能性がある場合は、例外が発生しないようにこのメソッドのロジックを変更します。
CA1063'App' で Dispose(bool) のオーバーライド可能な実装を提供するか、型を sealed としてマークします。Dispose(false) を呼び出す場合は、ネイティブ リソースのみがクリーンアップされます。Dispose(true) を呼び出す場合には、マネージド リソースとネイティブ リソースの両方がクリーンアップされます。
CA2000'new App()' が作成したオブジェクトへの参照がすべてスコープ外になる前に、そのオブジェクトの System.IDisposable.Dispose を呼び出してください。
CA1063'App.Dispose' を変更し、Dispose(true) を呼び出したのちに現在のオブジェクト インスタンスで GC.SuppressFinalize (Visual Basic の 'this' または 'Me') を呼び出して、結果を戻すようにします。
CA1816GC.SuppressFinalize(object) を呼び出すように App.Dispose() を変更します。これにより、ファイナライザーを導入する派生型で、その呼び出しのために 'IDisposable' を再実装する必要がなくなります。

所見

エラーの解説ページの修正方法が、IDisposableインターフェイスとして実装と書かれている事です。
CA1001:破棄可能なフィールドを所有する型は、破棄可能でなければなりません

IDisposableを追加する理由は、アンマネージリソースを解放することが目的だと知りました。
コンポーネントクラスは.NETフレームワークで管理されているリソースなのでアンマネージリソースではないのではないと思います。

アンマネージとマネージの考え方がそもそも間違っているのかもしれません。

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

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

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

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

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

Zuishin

2020/06/16 23:26

> IDisposableを追加する理由は、アンマネージリソースを解放することが目的だと知りました。 違います。
hasshy

2020/06/18 18:56

ご指摘いただきありがとうございます。 失礼しました。
Zuishin

2020/06/18 22:21

質問の大前提が間違っているのでまず正しい資料を読んでください。でなければ回答者の説明が理解できないと思います。
guest

回答2

0

ベストアンサー

こんにちは。

エラーコードの自動翻訳はいつもゴミなので意味不明ですが、要するに、

  • フィールドに IDisposable を実装する型を置いている場合、
  • そのクラス自身にも IDisposable を実装し、
  • Dispose メソッドはフィールドの Dispose メソッドを呼ぶ実装にする

というだけの話です。

フィールドに IDisposable を実装したオブジェクトがある、というのは、言い換えると「自オブジェクトが内部にリソースを持つ」ということになります。
内部にリソースを持つオブジェクトは、「それ自体がリソースである」と考えることができます。
そのため、リソースを能動的に破棄する方法を提供するために IDisposable の実装が必要になるのです。

あるいは、こちらが本題ですが、
フィールドに IDisposable を実装したオブジェクトを置かないように設計を変更できないか考えてください。
本来リソースというものは、「使うときに入手して、使い終わったらすぐに手放す」ように意識するものです。
リソースをフィールドに置くこと自体が不自然で、置いても良いのはよく考えた結果そうあるべきだと結論が出ている場合だけだと考えてください。

あとは、リソースとして振る舞わないのに IDisposable を実装している謎クラスとかは時々見かけますが、そういうのを相手するときはどうしようもないですね。

投稿2020/06/17 07:53

tamoto

総合スコア4103

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

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

Zuishin

2020/06/17 08:11

正しい回答なので高評価しましたが、今回の場合はおそらくアプリケーションが起動している間ずっと通知アイコンを出しておかなければいけないと推測できるので、App が持つのが適当かと思います。
tamoto

2020/06/17 08:28

WPF には明るくないですが、見た感じ App が保持するのが適当であることは自分も同意します。 効果は無くとも App クラスに IDisposable を実装して解決するとした場合、 > Appクラスそのものを大きく修正しないと解決出来ないエラーが発生しました。 というのは何が起きたのかが気になりますね。
Zuishin

2020/06/17 08:40

このコードからは特にエラーも警告も出ないので、別の要因だと思いますが、Windows Forms のコンポーネントを使うのに参照してないとかその手のことじゃないかと思います。
tamoto

2020/06/17 08:47

Core WPF + FxCopAnalyzers で App に IDisposable を実装してみましたが、App に sealed 修飾が必要になったくらいで特に何も起きませんでした。
hasshy

2020/06/18 18:55

ご回答いただきありがとうございます。 整理しきれていない部分があり失礼いたしました。 ご共有までにエラーについては追記いたしました。 重ね重ね申し訳ありませんが、リソースについてもう少し教えていただきたいです。 ソリューションエクスプローラーで項目追加したコンポーネントクラスを、今回のようにインスタンス化した場合はリソースとなるのでしょうか? > フィールドに IDisposable を実装したオブジェクトを置かないように設計を変更できないか考えてください。 > 本来リソースというものは、「使うときに入手して、使い終わったらすぐに手放す」ように意識するものです。 解釈が間違っていたら申し訳ありません。 フィールドで極力使わない設計と言うのは、 例えばAppのOnStartup関数で呼び出し、開放はガベレージコレクタに任せるような方法でしょうか?
tamoto

2020/06/18 23:53

「リソース」というのはもっと一般的な概念で、「『開始』と『終了』の2つの性質を持つ (== ライフタイムを持つ) オブジェクト」のことを指します。 IDisposable を実装したオブジェクトは、コンストラクタを「開始」、Dispose メソッドを「終了」とみなしてリソースとなるのです。 リソースの一番わかり易い例はファイルです。オープンとクローズの概念を備えていて、使うときに開いて使い終わったらすぐに閉じるイメージがつかめるでしょうか。 Component のインスタンスは IDisposable を備えるのでリソースである、ということになります。 「フィールドを極力使わない」というのは、「リソースはできる限り一瞬だけ開いてすぐ閉じるように使う」という一般論です。 今回の Component に関しては、App の開始時に作り App の終了時まで生き続けるため、フィールドに置くのは適切かと思います。 追記のエラーというか警告についてですが、 * Dispose メソッドは「終了」を記述する場所なので、中身が NotImplementedException のままじゃだめです。 * Dispose メソッドがフィールドの Dispose を呼んでいません。 * 今回は Dispose パターンを実装しないので、App クラスを sealed にする。 この3つをやっていないからです。IDE の言う通りではなく手で書いて直してください。
hasshy

2020/06/19 05:06

度々ありがとうございます。 リソースについてご説明頂きありがとうございます。 概念なのですね。 質問したときは気づかなかったのですが、コンポーネントクラスに最初から付与(?)されていた、Componentインターフェイスの中身を見たらIDisposableインターフェイスを指定されていたので腑に落ちました。 > 「フィールドを極力使わない」というのは、「リソースはできる限り一瞬だけ開いてすぐ閉じるように使う」という一般論です。 > 今回の Component に関しては、App の開始時に作り App の終了時まで生き続けるため、フィールドに置くのは適切かと思います。 承知しました。 また、警告内容について丁寧にご説明頂きありがとうございます。 そもそもの警告が、将来このクラスを継承する場合、IDisposableにしないといけないという警告と、 開放する処理が掛かれていないという事なのですね。 Appクラスは継承して使うものではないので、sealedクラスにするというのは理解できました。
guest

0

基本的に IDisposable インターフェイスを継承してないクラスはアンマネージドリソースは使ってないはずなので、リソースの解放はガベージコレクタに任せておけば良いです。プログラマが明示的に解放するコードを書く必要はありません。

自分でカスタムクラスを作っていて、それにアンマネージドリソースを使っているとか、IDisposable インターフェイスを継承したクラスを使っているなら話は別ですが。

Dispose パターンというのがあるので、ググって調べてみてください。Visual Studio には Dispose パターンの実装をサポートする機能があります。そのあたりもググると情報が得られると思います。

【追記】

下のコメント欄の 2020/06/19 09:52 の私のコメントで「Dispose パターンについて回答欄に追記しておきます」と書きましたが、それを以下に追記します。

参考にされている記事の「NotifyIcon クラス の ラッパー」の NotifyIcon というのが System.Windows.Forms 名前空間の NotifyIcon クラスのことであれば、そのクラスは System.ComponentModel 名前空間の Component クラスを継承しており、Component クラスは IDisposable インターフェイスを継承しているので、NotifyIconWrapper も Dispose が必要ということなのかもしれませんね。

クイックアクションとリファクタリングを参考に、IDisposableインターフェイスを実装しました。

そのコードは、以下の記事の一番上の画像にある「インターフェイスを実装します」を選択した結果ですよね? それは Dispose パターンを実装したのではなく、NotImplementedException 例外をスローする Dispose メソッドを実装しただけです。

Dispose パターン
http://surferonwww.info/BlogEngine/post/2019/05/31/dispose-pattern.aspx

Dispose パターンを実装するには「Dispose パターンを使ってインターフェイスを実装します」を選択します。そうすると以下の画像のようなコードが生成されてコードに追加されるはずです。

イメージ説明

その Dispose パターンの中で NotifyIconWrapper を Dispose するには、上のコードの protected virtual void Dispose(bool disposing) メソッド内のコメント「// TODO: dispose managed state (managed objects).」のところで

this.notifyIcon.Dispose();

とします。

それで少なくともエラーにはならないと思います。

ただし、WPF & 常駐アプリの App.xaml.cs でそういうことをしてリソースを開放できるのかどうかは、WPF には疎い自分には分かりません。

WPF & 常駐アプリということで、参考にされている記事では Dispose パターンは実装せず(Dispose パターンでは Dispose できない?)、OnExit メソッド内で Dispose しているのかもしれません。

投稿2020/06/16 23:23

編集2020/06/19 01:37
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

hasshy

2020/06/18 17:41

ご回答いただきありがとうございます。 > 自分でカスタムクラスを作っていて、それにアンマネージドリソースを使っているとか、IDisposable インターフェイスを継承したクラスを使っているなら話は別ですが。 質問したときは、マネージドリソースのみだと思っていたのですが、 コンポーネントクラス内でwincard.dllというライブラリを使用しており、アンマネージドリソースを使っているかもしれません。 Disposeパターンについて調べてみようと思います。
退会済みユーザー

退会済みユーザー

2020/06/19 00:52

> 質問したときは、マネージドリソースのみだと思っていたのですが、コンポーネントクラス内でwincard.dllというライブラリを使用しており、アンマネージドリソースを使っているかもしれません。 「コンポーネントクラス内でwincard.dll」というのが何だか分かりませんが・・・ 参考にされている記事の「NotifyIcon クラス の ラッパー」の NotifyIcon というのが System.Windows.Forms 名前空間の NotifyIcon クラスのことであれば、そのクラスは System.ComponentModel 名前空間の Component クラスを継承しており、Component クラスは IDisposable インターフェイスを継承しているので、NotifyIconWrapper も Dispose が必要ということなのかもしれませんね。 > Disposeパターンについて調べてみようと思います。 Dispose パターンについて回答欄に追記しておきます。
TN8001

2020/06/19 03:23

> App.xaml.cs でそういうことをしてリソースを開放できるのかどうか Mainを自分で実装すれば可能ですが、そこまでする必要もない気がします。 WPF:Mainメソッドを書き変えるには?[C#/VB]:.NET TIPS - @IT https://www.atmarkit.co.jp/ait/articles/1511/04/news027.html
hasshy

2020/06/19 05:29

度々ご回答いただきありがとうございます。 > 参考にされている記事の「NotifyIcon クラス の ラッパー」の NotifyIcon というのが System.Windows.Forms 名前空間の NotifyIcon クラスのことであれば、そのクラスは System.ComponentModel 名前空間の Component クラスを継承しており、Component クラスは IDisposable インターフェイスを継承しているので、NotifyIconWrapper も Dispose が必要ということなのかもしれませんね。 ご指摘ありがとうございます。 質問時は自分でIDisposableインターフェイスを書いていなかったので何故このエラーが出て来るのか分かっていなかったのですが、確かにComponentクラスのインターフェイスで指定してましたね。 また、Disposeパターンについても記載いただきありがとうございます。 > そのコードは、以下の記事の一番上の画像にある「インターフェイスを実装します」を選択した結果ですよね? はい。仰る通りです。 フィールドのコンポーネントクラスの開放方法についてもご指摘いただきありがとうございます。 参考にさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問