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

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

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

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

Q&A

解決済

3回答

1719閲覧

foreachでクラス内の変数を変える方法

rogita

総合スコア19

C#

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

0グッド

0クリップ

投稿2019/12/11 07:36

前提・実現したいこと

C#でクラス内の変数をforeachで変えたい場合はどうすれば,よろしいのでしょうか.
Data_AとData_Bの要素をランダムで選び,Data_Cを作られるのが理想です.

Data_A

列1列2列3
123

Data_B

列1列2列3
456

Data_C

列1列2列3
426

該当のソースコード

C#

1public class main() 2{ 3 4 5 Data Data_A=new Data(); 6 Data Data_B=new Data(); 7 Data Data_C=new Data(); 8 //Dataへの代入は省略 9 10 foreach 11  //続きはどう書けばいいのか? 12 13} 14 15public class Data 16{ 17 18 public int variable; 19 20 public Calculation Calc; 21 22 public int Section; 23 24 public enum Calculation 25 { 26 plus,minus,multiplication 27 }; 28}

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

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

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

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

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

Zuishin

2019/12/11 07:44

foreach の出番は無さそうです。
rogita

2019/12/11 07:55

では,foreachを使わない方法はあるのでしょうか?
Zuishin

2019/12/11 08:12

Data_A と Data_B を配列に入れ、シャッフルして最初の要素を取り出せばランダムにどちらかを選択できます。それを変数の回数繰り返せばいいでしょうが、変数には列挙子がないので、リフレクションを使わないのであれば foreach は使えません。高々三つの変数なので、リフレクションを使うまでもないと思います。
Zuishin

2019/12/11 08:17

シャッフルと書きましたが、それより 0 か 1 の乱数を生成する方が簡単ですね。
rogita

2019/12/11 12:56

リフレクションを使う場合を教えていただけないでしょうか.
Zuishin

2019/12/11 13:25

次のようになります。 速度的には不利で、初心者には難解で、可読性も比較的低くなります。 あえて使うことはないと思います。 using System; using System.Linq; namespace ConsoleApp1 { class Program { static void Main() { var dataA = new Data() { variable = 1, Calc = Data.Calculation.plus, Section = 3, }; var dataB = new Data() { variable = 4, Calc = Data.Calculation.minus, Section = 6, }; var fields = typeof(Data) .GetFields() .Where(a => new[] { nameof(Data.variable), nameof(Data.Calc), nameof(Data.Section)}.Contains(a.Name)) .ToList(); var dataArray = new[] { dataA, dataB }; var random = new Random(); Console.WriteLine(nameof(dataA)); Console.WriteLine(dataA); Console.WriteLine(nameof(dataB)); Console.WriteLine(dataB); Console.WriteLine(); Console.WriteLine("dataC"); for (int i = 0; i < 10; i++) { var dataC = new Data(); foreach (var field in fields) { field.SetValue(dataC, field.GetValue(dataArray[random.Next(dataArray.Length)])); } Console.WriteLine(dataC); } } } public class Data { public int variable; public Calculation Calc; public int Section; public enum Calculation { plus, minus, multiplication }; public override string ToString() => $"variable:{variable}, Calc:{Calc}, Section:{Section}"; } }
rogita

2019/12/11 13:27

参考にします。
guest

回答3

0

自己解決

Zuishinさんのコメントからリフレクションを調べたところ、
InvokeMemberを使って実装できることが分かりました.
以下のように実装しました.

C#

1 double half = 0.5; 2 3 4 // Random クラスの新しいインスタンスを生成する 5 System.Random hRandom = new System.Random(); 6 // 0.0 以上 1.0 以下の乱数を取得する 7 double dRandom = hRandom.NextDouble(); 8 9 Data Data_A=new Data(); 10 Data Data_B=new Data(); 11 Data Data_C=new Data(); 12 13 Type t = typeof(Data); 14 15 foreach (var f in t.GetFields()) 16 { 17 18 var Target=Data_A; 19 if(half>=dRandom) 20 { Target=Data_A;} 21 else 22 Target=Data_B; 23 24 var Target_Field = t.InvokeMember(f.Name, 25 BindingFlags.GetField, 26 null, 27 Target, 28 null); 29 30 t.InvokeMember(f.Name, 31 BindingFlags.SetField, 32 null, 33 Data_C, 34 new object[] {Target_Field}); 35 36 count+=1; 37 } 38 39

Zuishinさんが仰ったように,リフレクションでは速度が遅くなるので,Listを使うことを検討してみたいと思います.

投稿2019/12/12 01:22

rogita

総合スコア19

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

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

0

回答は他の回答者さんの言う通り、今回のお話ではループは必要ありません。

Excelをイメージされるとわかりやすいかもしれませんが、foreachループは1行ごとに行うようなものです。
Dataクラスのインスタンスは列が3つあるものを3つ作成しただけになります(リストや配列になっていないのでバラバラの状態です)。
Listや[]などでまとめた上で初めて使える状態になります。

投稿2019/12/11 12:17

Plan-B.0306

総合スコア105

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

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

0

foreachは配列のようなもの、より厳密に言えばIEnumerableを継承したものを対象にします。
2つのDataから1つのDataを作るならforeachは不要ですし、大量のDataの配列やListが対象の場合も今回の目的ではindexを乱数生成した方が容易なのでループの必要はないかと思います。

C#

1var random = new Random(); 2var randomData = new Data(); 3randomData.variable = dataArray[random.Next(dataArray.Length)].variable;

投稿2019/12/11 08:39

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問