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

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

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

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

Q&A

解決済

1回答

2391閲覧

1対多のモデルで1のインスタンス変数を多のクラスに引き渡す有効な方法

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

0グッド

0クリップ

投稿2017/01/15 08:24

とても些細な質問なのですが、お答えしていただけるとありがたいです。

現在C#で書いているプログラムの中であるクラスのインスタンスのメンバにDictionaryで管理された多のモデルがあります。

1のモデルのインスタンス生成時に、そのインスタンス内で管理されている多のモデルのインスタンスのみで有効な共通の変数を保持して多のモデルで定義されているメソッド内で使用したいのですが、多のモデルのインスタンス変数にこの値を持たせるのは同じインスタンスのメンバ間では冗長で,staticにすると1のモデルのインスタンス間で個別に設定することができないので、関数の引数で渡すという方法でやるのが普通なのかなと思いました。

しかし,その多のモデルの関数の中でその設定値を用いた再帰を行う必要がある処理があり,これによって引き渡された値は不変であるにも関わらず再帰の中でメモリ保持されて多数作られてしまうのではないかという懸念があり,(この質問書いてるうちに解決策を思いついてしまったのですが)変数への参照を引数に渡せばいいのだと思いましたが、もっといい方法ありますでしょうか。

ご意見いただけると嬉しいです。よろしくお願いいたします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

ご提示の状況を正しく解釈できてるか自信がないですが…
だいたい以下のような感じという認識であってますか??
(ご質問の際は書きかけでもいいので具体的なソースを載せていただいたほうが話が早いと思います)

C#

1//1のモデルとなるクラス 2public class SingleModel 3{ 4 private readonly Dictionary<int, MultiModel> multiDic; 5 6 private readonly DateTime singleValue; 7 8 public SingleModel() 9 { 10 //共通で使いたい変数値(仮にDateTimeとする) 11 this.singleValue = DateTime.Now; 12 13 //何らかのキーでDictionaryにして保持? 14 this.multiDic = Enumerable.Range(1, 10) 15 .ToDictionary(n => n, n => new MultiModel(n)); 16 } 17 18 public void CallDoSomething() 19 { 20 //多モデルオブジェクトすべてに対して関数呼び出し 21 foreach (var multi in multiDic.Values) 22 { 23 multi.DoSomething(this.singleValue); 24 } 25 } 26} 27 28//多のモデルとなるクラス 29public class MultiModel 30{ 31 public MultiModel(int key) 32 { 33 } 34 35 public void DoSomething(DateTime date) 36 { 37 //何かする 38 ... 39 40 //何らかの条件で再帰したりする 41 //→再帰する度にDateTimeが生成されて無駄なのでは?? 42 if (aCondition) DoSomething(date); 43 } 44}

そのうえで、「変数への参照を引数に渡せばいいのだ」というのは、
上記の MultiModel.DoSomething メソッドを
public void DoSomething(ref DateTime date) という形にするという意味でおっしゃってますか?

もしそういう意味でしたら、個人的には賛成できません。
「多のモデルの関数の中でその設定値を用いた再帰を行う必要がある」というのは
多モデルクラスの内部実装の都合であって、
内部実装の都合によって外部からの呼び出しI/Fが決められてしまうのはスマートでないように思います。
特に「ref」は「引数で渡した値が変更されるかもしれないよ」ということを表現する目的で
使うのが一般的なので、コードの保守に際しては混乱の元にもなるかと思います。

どうしても参照で渡したければ、

  • publicなDoSomethingメソッドで受け取った後に、そこからprivateな別メソッドを呼び出す際に

初めて引数をrefにする(そっちのprivateメソッドのほうで再帰する)

または

  • その値のみをメンバに持つクラスを作成し、引数としてそのクラスのオブジェクトを渡す

(structでなくclassならば参照渡しになる)

C#

1public class SingleValue //実際の用途にあわせて意味のある名前をつける 2{ 3 public DateTime Value { get; private set; } 4 5 public SingleValue(DateTime value) 6 { 7 this.Value = value; 8 } 9}

などの方法をとるほうが良いかなと思います。

ただ、多少再帰するからといって
パフォーマンスに影響するほどではないのでは?という気もします。
「予測するな、計測せよ」と言われるとおり、パフォーマンスについては
実際に動かしてみて初めて分かる部分も大きいです。
まずは素直な形で作って、動かしてみて、問題があれば初めて最適化を考えるでも良いかもしれません。

もっというと、不変な値なのであれば素直にコンストラクタで渡してしまっても良いようにも思いました。
「多のモデルのインスタンス変数にこの値を持たせるのは同じインスタンスのメンバ間では冗長」
という気持ちも確かにわかりますが、readonlyなメンバにしておけば整合が取れなくなる心配はありませんし、
オブジェクトの状態が安定するメリットのほうが大きいのではないかと思いました。

いろいろ書きましたが、正直にいうとケースバイケースです。
具体的な状況がわからない以上、あくまで「基本的にはこう考えます」程度の意見だと思ってください。

投稿2017/01/15 12:27

oika

総合スコア425

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

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

退会済みユーザー

退会済みユーザー

2017/01/16 01:21

ありがとうございます。回答に載せていただいたプログラムの例の解釈で合っています。 プログラムを載せるべきかと思いはしたのですが、ほぼ自分の中で答えが出てしまっていたことと、解る人には文章でも正しく伝わる内容(現にoikaさんには正しく伝わっています)であると思ったので、載せるのを怠りました。説明足らずで余計な労力をお掛けしてしまい申し訳ありません。 実験用のプログラムでビッグデータを突っ込むため、メモリは常に大量に使っているため最適化できるところを最適化したいという意図です。関数は一時変数生成し,実行終了まではガベージコレクタが働かない点で、値型で極端にサイズが大きなデータ(BigInteger)などを渡して再帰を行なった場合再帰回数によっては深刻になるのではないかという点で疑問に思いました。このような実装の違いの影響は実際些細だとは思うのですが,再帰を教えるような教材は値型でデータを渡すのでそれって本当は良くないのではとふと疑問に思った次第です。 >「予測するな、計測せよ」と言われるとおり、パフォーマンスについては 実際に動かしてみて初めて分かる部分も大きいです。 これはおっしゃる通りですね。一通りコードのリファクタリングが終わったらどれくらい変わったか計測したいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問