C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: 抽象クラスを継承したクラスのインスタンスについて


(過去ログ 178 を表示中)

[トピック内 17 記事 (1 - 17 表示)]  << 0 >>

■102293 / inTopicNo.1)  抽象クラスを継承したクラスのインスタンスについて
  
□投稿者/ 高橋 (1回)-(2023/08/16(Wed) 16:35:43)

分類:[C#] 

開発環境:Microsoft Visual Studio Professional 2022
使用言語のバージョン:.NET 6.0

抽象クラスを継承したクラスは静的にできず、インスタンスの作成が必須のようですが、
抽象クラスを継承したクラスを静的にしたいという設計はそもそも設計が間違いなのでしょうか。

以下のような状況です。
・プロジェクトを複数作成している。
・各プロジェクトで1つずつ設定の定数を定義する静的なconfigクラスを用意したい。
・各プロジェクトの設定の定数は大部分は全く同じで、一部だけが異なる。
※全く同じ例:出力されたファイルの保存先のフォルダ名
※一部異なる例:出力されたファイルの保存ファイル名

そのため、configクラスを抽象クラスとして用意し、各プロジェクトではそれを継承したconfig_2クラスを用意するつもりでした。
ただ、config_2クラスは各プロジェクトで1つだけで構わないにもかかわらず静的にできず、わざわざアプリインスタンスを手動で作成する必要があります。
別にそれでもいいのですが静的クラスという存在があるのに1度だけ必ずインスタンスを作るのも正しくないような気がして質問させていただいております。

以下、説明のためのサンプルコード


public static class Test
{
    public static void Main()
    {
        //パターン1(継承せずに静的クラスを用意した場合)
        Console.WriteLine(Config_SystemA.GetExportedFilePath());
        Console.WriteLine(Config_SystemB.GetExportedFilePath());

        //パターン2(継承して静的クラスを用意できない場合)
        Config_SystemA_2 config_SystemA_2 = new();  //このインスタンスを作りたくない。
        Console.WriteLine(config_SystemA_2.GetExportedFilePath());

        Config_SystemB_2 config_SystemB_2 = new(); //このインスタンスを作りたくない。
        Console.WriteLine(config_SystemB_2.GetExportedFilePath());
    }
}
//パターン1(継承せずに静的クラスを用意した場合)
public static class Config_SystemA
{
    private static string ExportToFolderName { get; } = "C:\\Users\\Desktop";
    private static string ExportedFileName { get; } = "systemA.txt";
    public static string GetExportedFilePath()
    {
        return ExportToFolderName + "\\" + ExportedFileName;
    }
}
public static class Config_SystemB
{
    private static string ExportToFolderName { get; } = "C:\\Users\\Desktop";
    private static string ExportedFileName { get; } = "systemB.txt";
    public static string GetExportedFilePath()
    {
        return ExportToFolderName + "\\" + ExportedFileName;
    }
}

//パターン2(継承して静的クラスを用意できない場合)
//抽象クラス
public abstract class Config_Base
{
    protected abstract string ExportToFolderName { get; }
    protected abstract string ExportedFileName { get; }
    public string GetExportedFilePath()
    {
        return ExportToFolderName + "\\" + ExportedFileName;
    }
}
public class Config_SystemA_2 : Config_Base
{

    protected override string ExportToFolderName { get; } = "C:\\Users\\Desktop";

    protected override string ExportedFileName { get; } = "systemA.txt";
}
public class Config_SystemB_2 : Config_Base
{

    protected override string ExportToFolderName { get; } = "C:\\Users\\Desktop";

    protected override string ExportedFileName { get; } = "systemB.txt";
}


※送信を失敗したようなので少し待ってから再送しています。(もし重複投稿になっていたらこちらは後で削除させていただきます。)

引用返信 編集キー/
■102294 / inTopicNo.2)  Re[1]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ 魔界の仮面弁士 (3681回)-(2023/08/16(Wed) 17:10:06)
2023/08/16(Wed) 17:21:27 編集(投稿者)

No102293 (高橋 さん) に返信
> 抽象クラスを継承したクラスは静的にできず、インスタンスの作成が必須のようですが、
> 抽象クラスを継承したクラスを静的にしたいという設計はそもそも設計が間違いなのでしょうか。

継承させたいのであれば、static 化せずに
Singleton 実装にすれば済みそうですが、
それでは都合が悪いのでしょうか?

処理の差し替えは、Properties.Settings.Default のように
内部的に行うか、Factory を別途用意するなどの準備は必要そうですが。
引用返信 編集キー/
■102295 / inTopicNo.3)  Re[2]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ 高橋 (2回)-(2023/08/16(Wed) 19:58:07)
早速の回答ありがとうございます。

PropertiesとFactoryを用意してさらにSingletop実装するのは確実そうですね。
PropertiesとFactoryを組み合わせる発想はありませんでした。(というかFactoryを使いこなしていませんでした。)



> 継承させたいのであれば、static 化せずに
> Singleton 実装にすれば済みそうですが、
> それでは都合が悪いのでしょうか?
インスタンスを間違えて2回も3回も立てることはなくなるためsingleton実装自体は悪くないと思っておりますが
プロジェクトで共通の設定値のため、プロジェクトの開始早々にインスタンスを用意せねばならず、
またクラスをまたぐ(※)ことが多い都合上、sigleton実装よりもstaticの方が楽だと思っております。

※Mainで立てたインスタンスを、Form1でも参照して、Form1から開かれたForm2でも参照して...ってするのなんか複雑になっていきそうな気がしませんか。

究極的にはコピペではstaticなものを用意することはできるので、どうしてコピペではできるのに継承ではstaticで実装できないのかという疑問が大きいです。
継承したものをstaticにできると困ることなさそうですが複雑になりすぎるからですかね。
引用返信 編集キー/
■102296 / inTopicNo.4)  Re[3]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ 魔界の仮面弁士 (3682回)-(2023/08/16(Wed) 20:19:56)
2023/08/16(Wed) 20:20:40 編集(投稿者)

No102295 (高橋 さん) に返信
> プロジェクトで共通の設定値のため、プロジェクトの開始早々にインスタンスを用意せねばならず、
> またクラスをまたぐ(※)ことが多い都合上、sigleton実装よりもstaticの方が楽だと思っております。

その Singleton インスタンスを static プロパティで管理しているなら、
「初回アクセス時にインスタンスを自動生成」する仕組みにできる気がします。

最近だと DI (依存性注入) での実装パターンもあるかな。

保持したい設定値が、固定値(たとえばファイル パス情報など)であれば、
Microsoft.Extensions.Configuration だけでもそこそこ管理できるかも。
https://zenn.dev/higmasu/articles/b3dab3c7bea6db
https://koudenpa.hatenablog.com/entry/2018/12/08/004332
https://learn.microsoft.com/ja-jp/dotnet/core/extensions/options-library-authors
引用返信 編集キー/
■102297 / inTopicNo.5)  Re[1]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ とっちゃん (784回)-(2023/08/16(Wed) 20:35:44)
No102293 (高橋 さん) に返信

> 抽象クラスを継承したクラスは静的にできず、インスタンスの作成が必須のようですが、
> 抽象クラスを継承したクラスを静的にしたいという設計はそもそも設計が間違いなのでしょうか。
> 
自分の場合ですが、このような設定クラス的なものは、設定ファイルを使うことを最初に検討します。

app.config や Properties.Settings などフレームワークが提供する機能を使うこともありますし
専用の設定ファイルを使うこともあります。
内容やデータの持続要件によっては、Propeties.Resources を使うこともあります。

実際、用意するデータによって、いずれのパターンも使っているので、一概にこれが良いと
お勧めすることもできません(状況次第ですべてが利用対象になり得るため)。

一応の指針としては、できるだけ既存の機能を利用するということは考えます。
あとは、既存機能で事足りるかどうかというところですかね。

今回サンプルとして挙げたものの場合、GetExportedFilePath メソッドさえ用意できれば良いので
おそらく、app.config か、Propetires.Settings あたりを使うかな?(プロジェクトの種類で何を使うかが変わる)

引用返信 編集キー/
■102298 / inTopicNo.6)  Re[4]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ とっちゃん (785回)-(2023/08/16(Wed) 20:36:38)
No102296 (魔界の仮面弁士 さん) に返信

> 最近だと DI (依存性注入) での実装パターンもあるかな。
>
> 保持したい設定値が、固定値(たとえばファイル パス情報など)であれば、
> Microsoft.Extensions.Configuration だけでもそこそこ管理できるかも。
> https://zenn.dev/higmasu/articles/b3dab3c7bea6db
> https://koudenpa.hatenablog.com/entry/2018/12/08/004332
> https://learn.microsoft.com/ja-jp/dotnet/core/extensions/options-library-authors

あー。DIもあった。最近使える場から離れてたからすっかり忘れてた…><
引用返信 編集キー/
■102299 / inTopicNo.7)  Re[1]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ WebSurfer (2774回)-(2023/08/16(Wed) 22:44:19)
No102293 (高橋 さん) に返信

なぜ abstract を継承するのかとか、なぜ static にできないのが問題なのかとかが理解
できていませんが・・・ (なんとなく、XY 問題ではないかという気がします)

> ※Mainで立てたインスタンスを、Form1でも参照して、Form1から開かれたForm2でも参照
> して...ってするのなんか複雑になっていきそうな気がしませんか。

とのことですから、Windows Forms アプリで、「抽象クラスを継承したクラス」から取得
したい構成情報が、

> ※全く同じ例:出力されたファイルの保存先のフォルダ名
> ※一部異なる例:出力されたファイルの保存ファイル名

というようなものなのですよね。

であれば、組み込みの機能として利用できる Settings.settings から情報を取得方法すれ
ば済むと思うのですが、それを使わない理由は何でしょう?

コードを見ると、「抽象クラスを継承したクラス」を使用する前に、"C:\\Users\\Desktop"
とか "systemA.txt" をアプリの違いに応じて設定しているようですが、そういうことは
Settings.settings でスコープを User にすれば目的は果たせるはずです。

具体例は以下の記事を見てください。

Settings.settings の使い方
http://surferonwww.info/BlogEngine/post/2021/06/05/how-to-get-and-set-values-in-settings-file.aspx
引用返信 編集キー/
■102300 / inTopicNo.8)  Re[2]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ 高橋 (3回)-(2023/08/17(Thu) 13:23:38)
魔界の仮面弁士さん、とっちゃんさん、WebSurferさん回答ありがとうございます。


みなさん、既存の機能を使うことをおすすめということはそもそも独自に設定クラスを用意しようとしている点がよくないんでしょうね。
ただ、後述いたしますがおっしゃっている通り、私の理解・説明不足からXY問題になっている気もします。
みなさんの回答を下に改めて質問を分解すると以下の2点になるんだと思います。
(1)Properties.settings等に定数を記載しようとするとコピペが増えて不便ではないでしょうか。
(2)Properties.settingsとか、独自に設計したstaticな設定クラスはインスタンスを作る必要がないのに、抽象クラスを継承した設定クラスではインスタンスを作らなければならないのはなんか違和感がありますがそういうものでしょうか。
※Properties.settingsしか使ったことがないのでProperties.settingsを例にしておりますが、その他の既存機能でも多分同様の疑問です。



魔界の仮面弁士さん

紹介いただいたリンクを拝見させていただきました。
Microsoft.Extensions.Configurationは初耳なのでしたが便利そうですね。
(まだ理解しきれていないので)これ使いますとは即答しかねるのですが後で熟読して使えないか頑張ってみます。

DIについても以下のページを下に雰囲気は理解しました。
ただ、interface使ったことないので雰囲気しか理解できていませんが、確かに目的の一部には合致するように感じます。
https://qiita.com/okazuki/items/a0f2fb0a63ca88340ff6


とっちゃんさん

できるだけProperties.settingsなど既存の機能を利用するということは考えます。
(既存の機能で達成できるような簡便なものについて)設定ファイルをstaticに使うこと自体が標準的な設計ではなさそうという理解をいたしました。



WebSurferさん

>組み込みの機能として利用できる Settings.settings から情報を取得方法すれば済むと思うのですが、それを使わない理由は何でしょう?
(Properties.SettingsとSettings.settingsは同じものを指しているという認識でいいんでしょうか?)
プロジェクトを複数作成するとプロジェクトの分だけSettings.settingsを記載する必要が出ますよね?
その場合、プロジェクトごとに大量のコピペが発生しそうでコピペはすればするほどメンテナンス性が低下するからよくないという認識でいるのでよくないことだと思っておりました。


>なぜ abstract を継承するのかとか、なぜ static にできないのが問題なのかとかが理解
>できていませんが・・・ (なんとなく、XY 問題ではないかという気がします)
「abstractを継承したい件」と「なぜstaticにできないのが問題なのかの件」はおそらく、2つの件なのでそれぞれ記載いたします。


以下、改めて質問を分解して記載しています。
・abstractを継承したい件
「(1)Properties.settings等に定数を記載しようとするとコピペが増えて不便ではないでしょうか。」という疑問
仮に
(1)全プロジェクトに共通の文字列(保存先フォルダ名等)が100個
(2)各プロジェクトに共通ではないが必ず存在する文字列(保存ファイル名等)が各10個
(3)各プロジェクトが独自に持っていたりもっていなかったりする文字列(各プロジェクト独自の定数)が各0個〜30個
あるとすると

【Settings.settingsなど、既存の機能を使用する場合】
(1) ⇒ 完全にコピペで可
(2) ⇒ コピペした後パラメーターのみの変更で可
(3) ⇒ 完全に独自に記載が必要になるので

【抽象クラスを用意する場合】
(1) ⇒ 抽象クラスで定義して変更なし。
(2) ⇒ 抽象クラスで定義しつつ、継承先で変更
(3) ⇒ 継承先で独自に定義

という理解なので抽象クラスにすればコピペする必要がなくメンテナンス性が高く記載できると考えておりました。


・なぜstaticにできないのが問題なのかの件
「(2)Properties.settingsとか、(中略)違和感がありますがそういうものでしょうか。」という疑問
厳密には問題ではなく疑問なので、「抽象クラスと継承されたクラスとはそういうものである。」と言われたら納得するのですが
上記のような設計の場合、プログラム段階で定義するのでstaticにできそうなのにできないんでしょうか。


うまくお伝えできていないようなのですがこれで過不足なく説明できているでしょうか。
引用返信 編集キー/
■102301 / inTopicNo.9)  Re[3]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ 魔界の仮面弁士 (3683回)-(2023/08/17(Thu) 16:44:50)
No102300 (高橋 さん) に返信
> 紹介いただいたリンクを拝見させていただきました。
> Microsoft.Extensions.Configurationは初耳なのでしたが便利そうですね。

.NET Framework では、Properties.Settings.Default を使うことが多かったですが、
.NET では appsettings.json ファイルを使う方法が推奨されています。
https://www.ipentec.com/document/csharp-dot-net-using-appsetting-json-in-console-application
https://learn.microsoft.com/ja-jp/dotnet/core/porting/modernize


Web 系で使われることが多いですが、コンソールアプリやデスクトップアプリでも利用可能な仕組みです。
参考までに、関連するパッケージを挙げておきます。
https://qiita.com/c-yan/items/3e0b2503d26693140457
https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.extensions.configuration

Microsoft.Extensions.Configuration.Abstractions
Microsoft.Extensions.Configuration.Binder
Microsoft.Extensions.Configuration.CommandLine
Microsoft.Extensions.Configuration.EnvironmentVariables
Microsoft.Extensions.Configuration.FileExtensions
Microsoft.Extensions.Configuration.Ini
Microsoft.Extensions.Configuration.Json
Microsoft.Extensions.Configuration.UserSecrets
Microsoft.Extensions.Configuration.Xml



> ただ、interface使ったことないので雰囲気しか理解できていませんが

抽象クラスのかわりに interface が使われることもありますね。
(もっとも、それが今回の問題の解決策になるかは別問題)

.NET Framework ではなく .NET の世界においての話になりますが、
C# 8 以降では、interface のメソッドに、クラス同様の「メソッドの実装」を持たせられるようになりました。
また、静的フィールドも宣言可能になっています(インスタンス フィールドは NG)。

さらに C# 11 以降だと、interface の静的メンバーを abstract/virtual にできるように拡張されました。
(抽象クラスだと、static abstract や static virtual は作れないですね)


> 抽象クラスを継承した設定クラスではインスタンスを作らなければならないのは

そもそも、継承されることが前提であるからこその "抽象" クラスですが、
その実装を作るためにはインスタンスが必要です。
(継承ではなくインターフェイス実装であれば、抽象静的メンバーを用意できますが、クラスではそうもいかない)

ただ、そのインスタンスを、外部から new させるかどうかは別の話だと思います。
たとえば「Brush b = Brushes.Red;」という処理で、
「abstract な Brush クラスを継承した SolidBrush クラスのインスタンス」が得られますが、
利用者側から見れば、インスタンスの作成を意識せずに利用できていますよね。



> (1)Properties.settings等に定数を記載しようとするとコピペが増えて不便ではないでしょうか。

そもそも、コピペするのは何故でしょうか。

XML ベースの app.config にしろ、Json ベースの appsettings.json にしろ、
メンバーを増やすのではなくメンバーの値を変えるだけなら、
設定ファイルを差し替えるだけで済むかと思います。
あるいは異なる部分のみを差分ファイルとして用意しておき、マージして読み込ませる機構もあります。

.dll にしてそれを参照している場合、複数のプロジェクトがあっても、
差し換えるのは呼び出し元(.exe)側のファイルだけで済みます。

プロジェクト設定次第では、
 appSettings.debug.json
 appSettings.release.json

 app.debug.config
 app.release.config
などとして、ビルド設定に応じて切り替えることもできますね。

https://marketplace.visualstudio.com/items?itemName=GolanAvraham.ConfigurationTransform
https://qiita.com/10size/items/d19b469fd19f5b6cfd0e
https://pg-life.net/csharp/appconfig/
https://qiita.com/m2tmk/items/c24e4d0eb30d820dd7b5
引用返信 編集キー/
■102302 / inTopicNo.10)  Re[3]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ WebSurfer (2775回)-(2023/08/17(Thu) 16:59:52)
No102300 (高橋 さん) に返信

あまりよく理解されてないようですね。

> (Properties.SettingsとSettings.settingsは同じものを指しているという認識でいいんでしょうか?)

ちょっと違います。

Properties.Settings の Properties は名前空間名で、Settings はクラス名です。一方、
Settings.settings は構成ファイルの名前です。

ターゲットフレームワークを .NET Framework 4.8 にして Windows Forms アプリを作る
と、プロジェクトに既存の Properties フォルダがあって、Settings.settings ファイル
はそのフォルダ下に配置するというのがデフォルトになり Properties が名前空間に含ま
れるので、その中の構成情報を参照しようとすると、

Properties.Settings.Default.Xxxxx

というようになるということです。

> プロジェクトを複数作成するとプロジェクトの分だけSettings.settingsを記載する必要が出ますよね?
> その場合、プロジェクトごとに大量のコピペが発生しそう

質問者さんの言う「抽象クラスを継承したクラス」ではコピペ以上に面倒なことになりま
せんか?

>【抽象クラスを用意する場合】
> (1) ⇒ 抽象クラスで定義して変更なし。
> (2) ⇒ 抽象クラスで定義しつつ、継承先で変更
> (3) ⇒ 継承先で独自に定義

とのことですけど、具体的な構成情報はすべて継承先ですべて定義しないとダメなはず。
例えば以下のように。違いますか?

【抽象クラス】

public abstract class A
{
// 抽象メソッドの宣言では実際の実装は用意されないので、メソッドの
// 本体はなく、メソッドの宣言は単にセミコロンで終わり、シグネチャ
// に続く中かっこ ({ }) はありません。
public abstract string GetExportedFilePath();

public abstract string GetExportedFileName();
}

【継承クラス】

public class B : A
{
public override string GetExportedFilePath()
{
return "C:\\Users\\Desktop";
}

public override string GetExportedFileName()
{
return "systemA.txt";
}
}

> メンテナンス性が低下するからよくないという認識でいるのでよくないことだと思っておりました。

保守性の問題を言うなら、構成情報を保存・取得するのに、普通は使わない抽象クラスとか
継承クラスを使う方が問題はあると自分は思うのですが?

自分が保守者の立場だったとしたら、普通でない実装はやめてくれとお願いすると思います。

引用返信 編集キー/
■102303 / inTopicNo.11)  Re[1]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ 魔界の仮面弁士 (3684回)-(2023/08/17(Thu) 19:02:37)
No102293 (高橋 さん) に返信
> 開発環境:Microsoft Visual Studio Professional 2022
> 使用言語のバージョン:.NET 6.0

それは「使用言語のバージョン」ではありません。
「ターゲット フレームワークのバージョン」です。

Visual Studio 2022 においては
.NET Core 2.2 以下および .NET Framework をお使いの場合、言語バージョンは通常、C# 7.3 になります。
.NET Core 3.x をお使いの場合、言語バージョンは通常、C# 8 になります。
.NET 5 をお使いの場合、言語バージョンは通常、C# 9 になります。
.NET 6 をお使いの場合、言語バージョンは通常、C# 10 になります。
.NET 7 をお使いの場合、言語バージョンは通常、C# 11 になります。

.NET 8 の場合、正式リリース後は C# 12 向けとなるでしょう。


これらはあくまでも既定値であり、.NET Framework 4.8.1 で C# 11 を選択したり、
.NET 6 で、あえて C# 3 を選択するといった組み合わせも可能ですが、
通常はほぼ間違いなく、上記の組み合わせでの運用となるはずです。
引用返信 編集キー/
■102304 / inTopicNo.12)  Re[3]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ WebSurfer (2776回)-(2023/08/18(Fri) 11:48:20)
No102300 (高橋 さん) に返信

ターゲットフレームワークが .NET 6.0 の WinForms アプリですよね。

であれば、構成情報の保存には json ファイルを使いそれから情報を取得するのが良さそうです。

具体例は以下の記事を見てください。

WinForms で構成情報とコンテキストの DI (CORE)
http://surferonwww.info/BlogEngine/post/2021/03/30/how-to-inject-configuration-and-dbcontext-in-windows-forms-application.aspx

それで、

> (1)全プロジェクトに共通の文字列(保存先フォルダ名等)が100個
> (2)各プロジェクトに共通ではないが必ず存在する文字列(保存ファイル名等)が各10個
> (3)各プロジェクトが独自に持っていたりもっていなかったりする文字列(各プロジェクト独自の定数)が各0個〜30個

の、(1) については json ファイルをコピペするだけで対処できます。

(2), (3) については、別にその情報を含めた json ファイルを作ってマージし、(2) は上書き、
(3) は追加するということができます。そういう機能が備わってます。具体例は以下の記事を見
てください。

環境別の appsettings.json (CORE)
http://surferonwww.info/BlogEngine/post/2020/09/23/appsettings-json-in-multiple-environments.aspx

上の記事は ASP.NET Core のものなので、プロジェクトに組み込みの機能がファイル名を見て
自動的に上書き・追加を行うようになってますが、それは自分でコードを書いても簡単にでき
ます。

例えば、前者の記事では appsettings.json から構成情報を取得しています。これを上で言う (1) 
とすると、(2), (3) については例えば別に appsettings.addition.json というファイルを作って
それに含め(ファイル名は任意)、builder.AddJsonFile で追加してやれば (2) は上書き、(3) は
追加ということができます。

具体的には以下のようにします。

using Microsoft.Extensions.Configuration;

namespace WinFormsApp5
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            var builder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false);

            builder.AddJsonFile("appsettings.addition.json", optional: false);

            // 追加・上書きされた結果
            IConfiguration config = builder.Build();

            // ・・・中略・・・
        }
    }
}

引用返信 編集キー/
■102306 / inTopicNo.13)  Re[2]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ 高橋 (4回)-(2023/08/20(Sun) 10:01:00)
魔界の仮面弁士さん、WebSurferさん

何度も丁寧な回答ありがとうございます。

>保守性の問題を言うなら、構成情報を保存・取得するのに、普通は使わない抽象クラスとか
>継承クラスを使う方が問題はあると自分は思うのですが?
>自分が保守者の立場だったとしたら、普通でない実装はやめてくれとお願いすると思います。

>XML ベースの app.config にしろ、Json ベースの appsettings.json にしろ、
>メンバーを増やすのではなくメンバーの値を変えるだけなら、
>設定ファイルを差し替えるだけで済むかと思います。
>あるいは異なる部分のみを差分ファイルとして用意しておき、マージして読み込ませる機構もあります。

>.dll にしてそれを参照している場合、複数のプロジェクトがあっても、
>差し換えるのは呼び出し元(.exe)側のファイルだけで済みます。


「設定クラスには差分があるけど何個もコピペでも作りたくない。」という私の状況については
・そもそも特殊な設定クラスを作る実装は普通ではない。
・一般的にはjsonファイルや、Properties.Settings.Defaultなどの既存の機能を使う。
・差分だけマージするような実装にすればコピペする必要もない。
と理解いたしました。

実際の使い方やいくつか掲示いただいたもののうちどれがもっとも適切なのかについてはまだ理解が及んでいないのですが
少なくとも特殊な抽象クラスを用意して云々という実装はやめます。

回答ありがとうございます。
解決済み
引用返信 編集キー/
■102307 / inTopicNo.14)  Re[3]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ WebSurfer (2777回)-(2023/08/20(Sun) 10:38:30)
No102306 (高橋 さん) に返信

抽象クラス+継承クラスを使った場合、

> (1)全プロジェクトに共通の文字列(保存先フォルダ名等)が100個
> (2)各プロジェクトに共通ではないが必ず存在する文字列(保存ファイル名等)が各10個
> (3)各プロジェクトが独自に持っていたりもっていなかったりする文字列(各プロジェクト独自の定数)が各0個〜30個

の、(1), (2), (3) すべての項目を継承クラスで一つ一つ定義しなければならず、

> 【抽象クラスを用意する場合】
> (1) ⇒ 抽象クラスで定義して変更なし。
> (2) ⇒ 抽象クラスで定義しつつ、継承先で変更
> (3) ⇒ 継承先で独自に定義

ということはできないと思っていますが、それを可能にする方法があるのでしょうか?
方法があれば教えてください。


No102304 でお勧めした、構成情報のストアに json ファイルを使ってマージする方法
について、詳細を以下の記事に書きましたので、興味があれば読んでください。

WinForms アプリで構成情報の上書き (CORE)
http://surferonwww.info/BlogEngine/post/2023/08/19/overwrite-configuration-information-in-windows-forms-application.aspx

上の記事では、(1) の情報が appsettings.json に、(2), (3) の情報が appsettings.Production.json
にあると思って読んでください。

引用返信 編集キー/
■102308 / inTopicNo.15)  Re[4]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ 高橋 (5回)-(2023/08/21(Mon) 08:36:00)
WebSurferさん

>No102304 でお勧めした、構成情報のストアに json ファイルを使ってマージする方法
>について、詳細を以下の記事に書きましたので、興味があれば読んでください。
なんとご丁寧にありがとうございます。
jsonファイルはまだ「シリアライズしたりデシリアライズしたりして(動的に設定値を)読み書きするためのもの」程度の使い方しかしたことがないので
マージ以前にアプリの構成情報の書き方から勉強中ですがなんとかたどり着かせていただきます。



>> 【抽象クラスを用意する場合】
>> (1) ⇒ 抽象クラスで定義して変更なし。
>> (2) ⇒ 抽象クラスで定義しつつ、継承先で変更
>> (3) ⇒ 継承先で独自に定義

>ということはできないと思っていますが、それを可能にする方法があるのでしょうか?
>方法があれば教えてください。

間違っている、よくないと言われた実装のソースコードを貼るのも変な話ですが
意図としては下記のようなものを作っておりました。


    public static class Test
    {
        public static void Main()
        {
            Config_SystemA config_SystemA = new();
            Console.WriteLine(Config_SystemA.CompanyName);
            Console.WriteLine((100*Config_SystemA.StandardTaxRate/100).ToString()+"円");
            Console.WriteLine(config_SystemA.GetExportedFilePath());
            Console.WriteLine(Config_SystemA.specialConst);

            Console.WriteLine();
            Console.WriteLine();

            Config_SystemB config_SystemB = new();
            Console.WriteLine(Config_SystemB.CompanyName);
            Console.WriteLine((100 * Config_SystemB.StandardTaxRate/100).ToString() + "円");
            Console.WriteLine(config_SystemB.GetExportedFilePath());
        }
    }
    public abstract class Config
    {
        //(1)にあたる共通部分
        private const string ExportToFolderName = "C:\\Users\\Desktop";
        public const string CompanyName = "高橋商事";
        public const int ReducedTaxRate_ = 8;
        public const int StandardTaxRate = 10;
        public string GetExportedFilePath()
        {
            return ExportToFolderName + "\\" + ExportedFileName;
        }
        //(2)にあたる非共通部分
        protected abstract string IPAddress { get; }
        protected abstract string ExportedFileName { get; }
    }
    public class Config_SystemA : Config
    {
        //(2)にあたる非共通部分の定義
        protected override string ExportedFileName { get; } = "systemA.txt";
        protected override string IPAddress { get; } = "255.255.255.1";
        //(3)にあたる独自部分
        public const string specialConst = "systemA専用定数";
    }
    public class Config_SystemB : Config
    {
        //(2)にあたる非共通部分の定義
        protected override string ExportedFileName { get; } = "systemB.txt";
        protected override string IPAddress { get; } = "255.255.255.2";
    }

引用返信 編集キー/
■102309 / inTopicNo.16)  Re[5]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ WebSurfer (2778回)-(2023/08/21(Mon) 12:32:47)
No102308 (高橋 さん) に返信

> 意図としては下記のようなものを作っておりました。

返答をありがとうございました。

「解決済み」マークをつけておきます。
引用返信 編集キー/
■102310 / inTopicNo.17)  Re[6]: 抽象クラスを継承したクラスのインスタンスについて
□投稿者/ WebSurfer (2779回)-(2023/08/21(Mon) 12:34:09)
「解決済み」マークをつけておきます。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -