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

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

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

引数が多いメソッドの引数のクラス化について

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

■103269 / inTopicNo.1)  引数が多いメソッドの引数のクラス化について
  
□投稿者/ 高橋 (1回)-(2024/08/08(Thu) 08:39:02)

分類:[C#] 

開発環境:Microsoft Visual Studio Professional 2022 (64 ビット) - Current Version 17.8.6
使用言語:C#
フレームワーク:.Net8.0

フォームで種々の情報を入力して、それを別のアプリケーションに取り込ませるためのCSVファイルを作成する処理があります。
また、CSVファイルを作成するのはフォーム1で作る場合もあれば、フォーム2で作る場合もあるためCSVファイルを作成する処理をメソッド化してどちらのフォームからも呼び出しています。
その際、CSVファイルを作成するメソッドの引数が非常に多くなり読みにくいのでクラス化しようと考えております。
これについて2件質問です。

(1)クラス化した場合、パラメーターを定義し忘れるミスをするのですがコンパイル時点で防ぐ方法はないでしょうか。
※クラスのコンストラクタの用意も考えましたが、その引数が多くなり本末転倒だったので断念しました。
※参照する側のnullチェックでミスには気づけるのですができればコンパイル時点で気づきたいです。

(2)内容的には構造体でも十分に見えますがクラスの方がよいのでしょうか。
※ネットで調べた限りはクラス化を紹介しているwebサイトはありましたが、あまり構造体の使用を紹介しているwebサイトは見つかりませんでした。

よろしくお願いいたします。

コードそのまま載せられないので概要になりますが以下のイメージです。

(現状)
【Form1】
private void Button1_Click(object sender, EventArgs e)
{
    MakeCSV(strParam1, strParam2, strParam3, intParam4, intParam5);
}

【Form2】
private void Button2_Click(object sender, EventArgs e)
{
    MakeCSV(strParam1, strParam2, strParam3, intParam4, intParam5);
}

【MakeCSV】
public void MakeCSV(string param1, string param2, string param3, int param4, int param5)
{
//省略
}


(作りたいもの)
【Form1】
private void Button1_Click(object sender, EventArgs e)
{
    CSVParam cSVParam = new();
    cSVParam.StrParam1 = strParam1;
    cSVParam.StrParam2 = strParam2;
    cSVParam.StrParam3 = strParam3;
    cSVParam.IntParam4 = intParam4;
    cSVParam.IntParam5 = intParam5;

    MakeCSV(cSVParam);
}

【Form2】
private void Button2_Click(object sender, EventArgs e)
{
    CSVParam cSVParam = new();
    cSVParam.StrParam1 = strParam1;
    cSVParam.StrParam2 = strParam2;
    cSVParam.StrParam3 = strParam3;
    cSVParam.IntParam4 = intParam4;

//このソースコードではintParam5を代入し忘れている。

    MakeCSV(cSVParam);
}

【MakeCSV】
public void MakeCSV(CSVParam cSVParam)
{
//省略
}

//実際にはUserCodeとかNameとか20件くらい。
public class CSVParam()
{
    string? StrParam1 { get; set;}
    string? StrParam2 { get; set;}
    string? StrParam3 { get; set;}
    int? IntParam4 { get; set;}
    int? IntParam5 { get; set;}
}

引用返信 編集キー/
■103270 / inTopicNo.2)  Re[1]: 引数が多いメソッドの引数のクラス化について
□投稿者/ kiku (436回)-(2024/08/08(Thu) 08:50:33)
No103269 (高橋 さん) に返信
> 開発環境:Microsoft Visual Studio Professional 2022 (64 ビット) - Current Version 17.8.6
> 使用言語:C#
> フレームワーク:.Net8.0
> 
> フォームで種々の情報を入力して、それを別のアプリケーションに取り込ませるためのCSVファイルを作成する処理があります。
> また、CSVファイルを作成するのはフォーム1で作る場合もあれば、フォーム2で作る場合もあるためCSVファイルを作成する処理をメソッド化してどちらのフォームからも呼び出しています。
> その際、CSVファイルを作成するメソッドの引数が非常に多くなり読みにくいのでクラス化しようと考えております。
> これについて2件質問です。
> 
> (1)クラス化した場合、パラメーターを定義し忘れるミスをするのですがコンパイル時点で防ぐ方法はないでしょうか。
> ※クラスのコンストラクタの用意も考えましたが、その引数が多くなり本末転倒だったので断念しました。
> ※参照する側のnullチェックでミスには気づけるのですができればコンパイル時点で気づきたいです。
> 
> (2)内容的には構造体でも十分に見えますがクラスの方がよいのでしょうか。
> ※ネットで調べた限りはクラス化を紹介しているwebサイトはありましたが、あまり構造体の使用を紹介しているwebサイトは見つかりませんでした。
> 
> よろしくお願いいたします。

良い方法が思いつかなかったので
単純に下記のように改行したらどうでしょうか?
※ご要望には合わないんだろうなとは思っています。

【Form1】
private void Button1_Click(object sender, EventArgs e)
{
    MakeCSV(
        strParam1,
        strParam2,
        strParam3,
        intParam4,
        intParam5
        );
}

引用返信 編集キー/
■103271 / inTopicNo.3)  Re[1]: 引数が多いメソッドの引数のクラス化について
□投稿者/ Hongliang (1300回)-(2024/08/08(Thu) 09:56:09)
requiredキーワードがちょうどよさそうです。
https://learn.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/required

ちなみにC#コンパイラさえ新しいのを使えるのであれば、.NET (Fx)のバージョンがだいぶ古くても使えるそうです。
https://xin9le.hatenablog.jp/entry/2022/12/05/004601
引用返信 編集キー/
■103272 / inTopicNo.4)  Re[2]: 引数が多いメソッドの引数のクラス化について
□投稿者/ kiku (437回)-(2024/08/08(Thu) 10:08:50)
No103271 (Hongliang さん) に返信
> requiredキーワードがちょうどよさそうです。
> https://learn.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/required
>
> ちなみにC#コンパイラさえ新しいのを使えるのであれば、.NET (Fx)のバージョンがだいぶ古くても使えるそうです。
> https://xin9le.hatenablog.jp/entry/2022/12/05/004601

おおお、すばらしい。
.NETFrameWork4.8,1で利用できないのが残念。
引用返信 編集キー/
■103273 / inTopicNo.5)  Re[3]: 引数が多いメソッドの引数のクラス化について
□投稿者/ Hongliang (1301回)-(2024/08/08(Thu) 10:28:30)
ん?
2つ目のリンクで、.NET Framework 2.0でも動いたと報告されていますが。
Visual Studioのバージョンによっては古いコンパイラしか使えなくてビルドできないでしょうけど。
引用返信 編集キー/
■103274 / inTopicNo.6)  Re[4]: 引数が多いメソッドの引数のクラス化について
□投稿者/ kiku (438回)-(2024/08/08(Thu) 10:50:58)
No103273 (Hongliang さん) に返信
> ん?
> 2つ目のリンクで、.NET Framework 2.0でも動いたと報告されていますが。
> Visual Studioのバージョンによっては古いコンパイラしか使えなくてビルドできないでしょうけど。

確かに、動いたとの記述があったので下記試してみました。

.NETFrameWork4.8,1、WinFormのプロジェクトを作って、
csprojに下記のみ追加
 <LangVersion>11.0</LangVersion>
 <Nullable>enable</Nullable>
その他は2つ目のリンクの通りに実装。
下記のinitのところで
 public bool IsOptional { get; init; }
下記エラーが発生しました
 CS0518	定義済みの型 'System.Runtime.CompilerServices.IsExternalInit' は定義、またはインポートされていません

自分の技術力ではこれを解決することは難しい。
※おそらく定義の足りないものを追加すればできるんだろうとは思います。

引用返信 編集キー/
■103275 / inTopicNo.7)  Re[5]: 引数が多いメソッドの引数のクラス化について
□投稿者/ Hongliang (1302回)-(2024/08/08(Thu) 10:56:24)
.NET 5 未満でも C# 9.0 の init アクセサを利用する - xin9le.net
ってリンクが記事中にありますよ。
引用返信 編集キー/
■103276 / inTopicNo.8)  Re[6]: 引数が多いメソッドの引数のクラス化について
□投稿者/ kiku (439回)-(2024/08/08(Thu) 11:02:39)
No103275 (Hongliang さん) に返信
> .NET 5 未満でも C# 9.0 の init アクセサを利用する - xin9le.net
> ってリンクが記事中にありますよ。

お、できました。

var test = new Class1() { test1="", test2="", test3=""};

namespace WindowsFormsApp1
{
internal class Class1
{
public required string test1 { get; set; }
public required string test2 { get; set; }
public required string test3 { get; set; }
}
}

namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
internal sealed class RequiredMemberAttribute : Attribute
{ }

[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
internal sealed class CompilerFeatureRequiredAttribute : Attribute
{
public CompilerFeatureRequiredAttribute(string featureName)
{
FeatureName = featureName;
}

/// <summary>
/// The name of the compiler feature.
/// </summary>
public string FeatureName { get; }

/// <summary>
/// If true, the compiler can choose to allow access to the location where this attribute is applied if it does not understand <see cref="FeatureName"/>.
/// </summary>
public bool IsOptional { get; init; }

/// <summary>
/// The <see cref="FeatureName"/> used for the ref structs C# feature.
/// </summary>
public const string RefStructs = nameof(RefStructs);

/// <summary>
/// The <see cref="FeatureName"/> used for the required members C# feature.
/// </summary>
public const string RequiredMembers = nameof(RequiredMembers);
}

internal sealed class IsExternalInit
{ }
}

引用返信 編集キー/
■103277 / inTopicNo.9)  Re[7]: 引数が多いメソッドの引数のクラス化について
□投稿者/ kiku (440回)-(2024/08/08(Thu) 11:16:08)
No103276 (kiku さん) に返信
> ■No103275 (Hongliang さん) に返信
>>.NET 5 未満でも C# 9.0 の init アクセサを利用する - xin9le.net
>>ってリンクが記事中にありますよ。
> 
> お、できました。

        private void Form1_Shown(object sender, EventArgs e)
        {
            //requiredを利用すると下記がエラーになるので
            //var test1 = new Class1();

            //結局下記の書き方になりそう
            var test2 = new Class1() {
                test1 = "",
                test2 = "",
                test3 = ""
            };

            //上記と大差ないので、改行でも良いかも
            var m1 = "";
            var m2 = "";
            var m3 = "";
            method(
                m1,
                m2,
                m3
                );
        }

        private void method(string m1,string m2,string m3)
        {
        }

引用返信 編集キー/
■103278 / inTopicNo.10)  Re[8]: 引数が多いメソッドの引数のクラス化について
□投稿者/ 高橋 (2回)-(2024/08/09(Fri) 08:06:11)
No103277 (kiku さん) に返信
> ■No103276 (kiku さん) に返信
>>■No103275 (Hongliang さん) に返信
kiku さん、Hongliang さんありがとうございます。

requiredキーワード便利ですね。
C#9.0以降でない場合はいろいろと不都合があるようですが、今回に限っては問題もなさそうですし大変助かります。

> //結局下記の書き方になりそう
(中略)
> //上記と大差ないので、改行でも良いかも
可読性が上がること、setした後加工したデータをgetできること、他の処理にも流用でき得ることからクラスで設定できるのは非常に助かります。
※流用の是非はともかく...

回答ありがとうございます。
解決済みにさせていただきます。
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


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

このトピックに書きこむ