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

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

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

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

4回答

4178閲覧

C#でPythonのように引数にリストや辞書をアンパックしたものを渡したい

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

1グッド

0クリップ

投稿2021/08/05 06:57

編集2021/08/05 07:27

前提・実現したいこと

Unity内のC#で引数を渡す際に,Pythonのようにリストや辞書をアンパックして渡したいです.

Unity, C# 初心者です.
調べても解決しなかったので質問させていただきます.
詳しい方ご教授お願い致します.

以下 pythonでの例

python

1class Character: 2 def __init__(self, name, hp, mp, atk, def_): 3 self.name = name 4 self.hp = hp 5 self.mp = mp 6 self.atk = atk 7 self.def_ = def_ 8 9def main(): 10 character_list = ["hogeman", 10, 10, 10, 10] 11 hogeman_list = Character(*character_list) 12 13 character_dict = {"name": "hogman", "hp": 10, "mp": 10, "atk": 10, "def_": 10} 14 hogeman_dict = Character(**character_dict) 15 16if __name__ == "__main__": 17 main()

上記pythonの例のように以下のようにC#でも記述したい.

C#

1using System.Collections.Generic; 2 3public class Character { 4 public string name; 5 public int hp; 6 public int mp; 7 public int atk; 8 public int def; 9 10 public Character(string name, int hp, int mp, int atk, int def) { 11 this.name = name; 12 this.hp = hp; 13 this.mp = mp; 14 this.atk = atk; 15 this.def = def; 16 } 17} 18 19public class CharacterManager { 20 public void CharacterInstance() { 21 var character_list = new List<T>() {"hogeman", 10, 10, 10, 10}; 22 var hogeman_list = new Character(/* アンパックされた */character_list); 23 24 var character_dict = new Dictionary<string, T>() { 25 {"name", "hogeman"}, 26 {"hp", 10}, 27 {"mp", 10}, 28 {"atk", 10}, 29 {"def", 10}, 30 }; 31 var hogeman_dict = new Character(/* アンパックされた */character_dict); 32 33 // 次のようにはしない 34 var yaritakunai = new Character(Character(character_list[0]), character_list[1], ~~~~ ); 35 var yaritakunai = new Character(Character(character_dict["name"]), character_dict["hp"], ~~~~ ); 36 } 37}

なお,次の前提でやっています.

  • フィールドに合わせたリスト,辞書を用意する
  • フィールドの種類は増減する

バージョン

  • Unity 2020.3.13f1
  • .NET 4.0
TN8001👍を押しています

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

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

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

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

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

guest

回答4

0

Pythonのようにリストや辞書をアンパックして渡したい

C# ではアンパックに相当する機能はありません。TN8001 さんの回答のように Tuple を使う方法が辛うじて似ていると思います。


mori.hey さんの 2021/08/05 16:59 のコメントより

リストや辞書を引数にしたいクラスや関数が出来るたびにこのような記述をするのでしょうか.

それだと少し冗長な気がするのですが,皆さんこのように実装されているのでしょうか.
短く記述できる方法ご存知でしたら教えていただけると助かります.

そもそもアンパックを使わなければ冗長にならないかと思います。

character_dict の場合はわざわざ Dictionary に逃がすのではなく直接 Character のインスタンスを作成すれば良いかと思います。

C#

1var character = new Character("hogeman", 10, 10, 10, 10);

仮に character_dict のデータの取得元が JSON や CSV、データベースなのであれば、Dictionary にわざわざ変換するコードを書くのではなく、ライブラリを使いましょう。大体のライブラリは読み込んだコンテンツを直接特定のオブジェクトに変換する機能があります。
Json.NET とか CsvHelper とか Entity Framework とか。

character_list の場合はそもそもキーがない値のみの状態を持つこと自体がよくありません。
これでは name プロパティと hogeman という値をシンプルに紐付けることができないからです。

Character クラスのコンストラクタの引数の位置と character_list の添字で紐付けることはできますが、それを行うにはリフレクションを使う必要があり、とても複雑な実装になります。

わざわざリフレクションを使うぐらいであれば、キーを持たせれば良いだけです。
もしキーを持たせられない背景があるならそちらを先に解決するべきです。

よって character_dict, character_list のような初期化をしない実装がシンプルです。
もしアンパックを使うこと自体が目的と化していると思われたら、上記のようなアプローチで作り方を考え直したほうが良いかもしれません。

投稿2021/08/06 02:33

編集2021/08/06 02:43
BluOxy

総合スコア2663

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

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

退会済みユーザー

退会済みユーザー

2021/08/06 03:32

ご回答ありがとうございます. この質問の一番の目的は, Pythonのアンパックのような便利な機能はC#にはないのか, ないのならば諸先輩方はどのような工夫を凝らしているのかお伺いすることでした. ここまでの皆様のご回答で,なさそうだなということがわかったので実装の方に目を向けてみようと思います. アドバイスありがとうございます. 困ったら別のエントリで質問するつもりだったのですが, 回答者様はUnityにもお詳しいようなのでこちらでアドバイスいただきたいです. このアンパックについての質問は,「ScriptableObject から 実際のふるまいが実装されたclass objectへのスマートな値の受け渡し」に悩んだ際のPythonの知識を活かした解決案だったのですが, このスマートな受け渡しについて何か妙案ございますでしょうか. 実際のふるまいを持ったclass(Character classの拡張版)は ScriptableObjectのfieldの全てのfieldを持っています. また,ScriptableObjectは自身のfieldをListやDictionaryで返す機能を持たせました. 不都合あれば無視して頂いて構いません. よろしくお願いします.
BluOxy

2021/08/06 04:18 編集

(あまり Unity は詳しくありませんが、わかる範囲で書きます) Character クラスのコンストラクタの引数に ScriptableObject ただ1つを渡せば良い気がします。 var characterStatus = ScriptableObject.CreateInstance<CharacterStatus>(); var character = new Character(characterStatus); 上記のような形で解決しなさそうであれば、ScriptableObject 周りに関してここで長く議論するのは不適当になってきますから、別の質問を立てましょう。
退会済みユーザー

退会済みユーザー

2021/08/06 04:03

本来の範囲を超えた質問へのご回答ありがとうございます. Unityでの設計思想への理解が未熟なため, ScriptableObejectのインスタンスをそのまま渡していいのかためらっていました. もう少し考えてみます,ありがとうございます.
guest

0

ベストアンサー

注)私はUnityに詳しくないので、mori.heyさんの環境で使用できるのかはわかりません。

Unity内のC#で引数を渡す際に,Pythonのようにリストや辞書をアンパックして渡したいです.

なぜタプルが出てこないのかという気がしますが、C#にもValueTupleというものがあります。

タプル型 - C# リファレンス | Microsoft Docs
タプルとその他の型の分解 | Microsoft Docs

これを利用すれば、ほぼ同じような使用感になるんじゃないでしょうか。

本当はrecordが使えればいうことないんですが、これはまだ使えないんでしょうね^^;
C# 9.0 の新機能 - C# ガイド | Microsoft Docs
レコード型 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C

Unityではありません。コンソールアプリです。

cs

1using System; 2 3namespace Questions352883 4{ 5 class Program 6 { 7 static void Main() 8 { 9 // ValueTuple 10 var valueTuple = new Character(("hogeman", 1, 2, 3, 4)); 11 Console.WriteLine(valueTuple); // name:hogeman, hp:1, mp:2, atk:3, def:4 12 13 // あくまで順番しか見ない。名前を付けたところで順番が変わるわけでも名前を間違えても関係ない 14 // ※警告はでるので間違いに気が付かないというわけではない。 15 // 警告 CS8123 ターゲット型 '(string name, int hp, int mp, int atk, int def)' によって異なる名前が指定されている、または名前が何も指定されていないため、タプル要素名 '○○' は無視されます。 16 valueTuple = new Character(("hogeman", mp: 1, hp: 2, hoge: 3, 4)); 17 Console.WriteLine(valueTuple); // name:hogeman, hp:1, mp:2, atk:3, def:4 18 19 20 // record 21 var record = new Character(new CharacterParams("hogeman", 1, 2, 3, 4)); 22 Console.WriteLine(record); // name:hogeman, hp:1, mp:2, atk:3, def:4 23 24 // コンパイルエラー 25 // 「名前付き引数」のルールを守らないとコンパイルできないので間違いようがない 26 // [名前付き引数と省略可能な引数 - C# プログラミング ガイド | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments) 27 // [オプション引数・名前付き引数 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C](https://ufcpp.net/study/csharp/sp4_optional.html#named) 28 //record = new Character(new CharacterParams("hogeman", mp: 1, hp: 2, hoge: 3, 4)); 29 //record = new Character(new CharacterParams("hogeman", mp: 1, hp: 2, hoge: 3, hp: 4)); 30 //record = new Character(new CharacterParams("hogeman", hp: 1, hp: 2, atk: 3, def: 4)); 31 //record = new Character(new CharacterParams(1, 2, 3, 4, name: "hogeman")); 32 33 record = new Character(new CharacterParams("hogeman", 1, def: 2, atk: 3, mp: 4)); 34 Console.WriteLine(record); // name:hogeman, hp:1, mp:4, atk:3, def:2 35 36 record = new Character(new CharacterParams(hp: 1, def: 2, atk: 3, mp: 4, name: "hogeman")); 37 Console.WriteLine(record); // name:hogeman, hp:1, mp:4, atk:3, def:2 38 } 39 } 40 41 record CharacterParams(string name, int hp, int mp, int atk, int def); 42 43 class Character 44 { 45 string name; 46 int hp; 47 int mp; 48 int atk; 49 int def; 50 51 public Character(string name, int hp, int mp, int atk, int def) 52 { 53 this.name = name; 54 this.hp = hp; 55 this.mp = mp; 56 this.atk = atk; 57 this.def = def; 58 } 59 60 // ValueTuple用 61 public Character((string name, int hp, int mp, int atk, int def) @params) 62 { 63 (name, hp, mp, atk, def) = @params; 64 } 65 66 // record用 67 public Character(CharacterParams @params) 68 { 69 (name, hp, mp, atk, def) = @params; 70 } 71 72 public override string ToString() 73 { 74 return $"name:{name}, hp:{hp}, mp:{mp}, atk:{atk}, def:{def}"; 75 } 76 } 77}

投稿2021/08/05 12:09

編集2023/07/28 15:09
TN8001

総合スコア9862

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

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

退会済みユーザー

退会済みユーザー

2021/08/06 00:48 編集

Tupleは考えたんですが、そこまで楽になるかと言われると疑問がありますし、パラメータ数の変動があった場合に死にそうな気がします。
TN8001

2021/08/06 02:09

> Tupleは考えたんですが、そこまで楽になるかと言われると疑問があります 少なくともListやDictionaryよりは楽だと思うのですが、何か楽の基準が違いますか? (私の楽さ基準はPythonの記述に近い・記述文字数) > パラメータ数の変動があった場合に死にそうな気がします。 引数の数や型が違うとエラーですので、堅牢だと思うのですが「いちいち修正がいる」という意味でしょうか?(これはよしあしですね) 個人的にexpression-bodied functionが好きなので、 public Character(string name, int hp, int mp) => (this.name, this.hp, this.mp) = (name, hp, mp); これはよく使っています^^ UnityもScriptableObjectもわからないんですが、リフレクションがありなら全自動にもできそうですがどうなんでしょうね^^; 私もPythonからC#に来た身ですので、mori.heyさんのフラストレーションもわからなくもないです。
Zuishin

2021/08/06 02:23

まず List や Dictionary として(しかも両方の形があり得る)データが存在しているということが気持ち悪いです。 動的に作成するにしても、作成したその時点で型を決められるような仕組みができそうかどうか検討したいです。 でなければ、これ一つだけではなく、同じ問題を解決しなければならないクラスが後から後から出てきそうです。
Zuishin

2021/08/06 02:26

要するに、List や Dictionary からではなく、Stream や string や DataTable から Character オブジェクトを作成することを考える方が私は望ましいと思います。
退会済みユーザー

退会済みユーザー

2021/08/06 02:41

そうですね。 Pythonでこうだったから、でクラス設計やデータ設計を決める事自体があまり良くない気がします。
退会済みユーザー

退会済みユーザー

2021/08/06 03:43

TN8001様: ご回答ありがとうございます!! ValueTupleの使用感,アンパックに一番近そうです!ありがとうございます. この質問の回答に一番近いのでベストアンサーにさせていただきます. ただ,諸先輩方が申されている通り, Unity初心者の自分がUnityのデータのあれこれでTupleを使いこなすのは, 少し難しそうです. pyhonのようにtuple(hoge_list)でtupleに変換出来なさそうなので少し勉強してきます. 丁寧なご回答ありがとうございました,今後の参考にさせていただきます.
退会済みユーザー

退会済みユーザー

2021/08/06 03:58

Zuishin様: 見ていらっしゃいますでしょうか. 私の質問に関しての議論ありがとうございます. いくつか私から回答したいと思います. > List や Dictionary として(しかも両方の形があり得る)データが存在しているということが気持ち悪いです。 存在していません. 実際の実装ではcsvから保存したScriptableObjectが存在しています. そのScriptableObjectからChracter objectを作成する際のデータの形としてListやDictionaryが考えられた,ということです. > 動的に作成するにしても、作成したその時点で型を決められるような仕組みができそうかどうか検討したいです。 ScriptableObjectのfieldに型を指定しています. csvからScriptableObjectへの変換の際には,名称指定でcsvから読み込んだstringから変換しています. > List や Dictionary からではなく、Stream や string や DataTable から Character オブジェクトを作成することを考える方が私は望ましいと思います。 先述の通り,ScriptableObject から Chracter object を作成することを考えたうえでのListやDictionaryでした. わかりにくい質問で申し訳ございませんでした.
guest

0

最初に与えるデータをJSONにしてデシリアライズするのはどうでしょう?

投稿2021/08/05 07:50

YAmaGNZ

総合スコア10489

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

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

退会済みユーザー

退会済みユーザー

2021/08/05 08:35

少しUnityでのjsonの扱いについて調べてみましたが, ScriptableObject -> json -> class object が簡単そうなので勉強してみようと思います! 元々の想定が csv -> ScriptableObject(Characterのデータ) -> dict or list -> class object(Character) だったのでとてもありがたいです. 勉強してコード化してみたいと思います.ありがとうございます.
guest

0

CharacterクラスにListやDictionaryを受け取るコンストラクタを定義すればよいのでは?

投稿2021/08/05 07:33

編集2021/08/05 07:35
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2021/08/05 08:00 編集

ご回答ありがとうございます. 以下のようなコンストラクタを追加しろということですね. ``` C# public Character(List<T> status_list) { this.name = status_list[0]; this.hp = status_list[1]; . . . } public Character(Dictionary<string, T> status_dict) { FieldInfo field = this.GetType().GetField(status_dict.Key); field.SetValue(this, status_dict.Value); } ``` 確かに解決できそうです.ありがとうございます. ですが,リストや辞書を引数にしたいクラスや関数が出来るたびにこのような記述をするのでしょうか. それだと少し冗長な気がするのですが,皆さんこのように実装されているのでしょうか. 短く記述できる方法ご存知でしたら教えていただけると助かります.
退会済みユーザー

退会済みユーザー

2021/08/05 08:25 編集

ベースになるクラスを作って、それを継承すればよいのではないでしょうか。 ただ、Dictionaryはある程度汎用性持たせられるでしょうが、Listの場合は代入のコード書くか、プロパティとListの順序をマッチングさせる別の情報でもないとどうにもならないですね。 辞書順に代入するみたいなルール決めて、プロパティをソートしたList作っておいて代入とかは可能かもしれないですが、保守考えると正直Listはやめたほうがよいのではないかと。
退会済みユーザー

退会済みユーザー

2021/08/05 08:42

汎用的に継承元になるクラスを作成するということですね. アンパックできなければ,関数の引数への応用をあきらめて, 取ろうとしていた方法の一つでした. ご教授ありがとうございます.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問