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

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

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

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

Unity

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

Q&A

解決済

1回答

2901閲覧

Unity,C#: プロパティのオーバーロードはできないのか,もしくはその代替手段にはどんなものがあるのか?

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

Unity

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

0グッド

0クリップ

投稿2021/09/21 08:39

編集2021/09/21 14:15

背景

Unity,C# 初心者です.
Unityの不便な点を丸めるためにMonoBehaviorを継承して,
MonoBehaviourの代わりに基底クラスになるクラスを作成しています.
一例として,
ゲームオブジェクトの親要素にtransformを経由せずにアクセスできるようにしようと思っています.
(parentがtransformからアクセスしないといけないことがHierarchyの見た目との直感に反しややこしい)

問題

上記の解決として以下のようにプロパティで記述しました.

C#

1using UnityEngine; 2 3public class BaseClass : MonoBehaviour { 4 public GameObject Parent { 5 get { return this.transform.parent.gameObject; } 6 set { this.transform.parent = value.transform; } 7 } 8}

これだともしTransformを渡すときにはBaseClass.transform.parent = Transformなので,
TransformもGameObjectと同じようにわたせるように、
つまりBaseClass.Parent = Transformにもしたいと思ったのですが,以下のようにオーバーロードできません.

C#

1using UnityEngine; 2 3public class BaseClass : MonoBehaviour { 4 5 // プロパティのオーバーロード 出来ない 6 public GameObject Parent { 7 get { return this.transform.parent.gameObject; } 8 set { this.transform.parent = value.transform; } 9 } 10 public Transform Parent { 11 set { this.transform.parent = value; } 12 } 13}

質問内容

上記のようなオーバーロードはC#の機能的にできないと思うのですが,
ジェネリック的なもの(詳しくないです)を使えばプロパティで実装できますでしょうか.

また,ジェネリック以外でのプロパティでの実装方法,
プロパティ以外での実装方法は存在しますでしょうか.

以下のようにプロパティではなく関数ではオーバーロードできることは知っています.

C#

1using UnityEngine; 2 3public class BaseClass : MonoBehaviour { 4 5 // 関数のオーバーロード 6 public GameObject Parent() { 7 return this.transform.parent.gameObject; 8 } 9 public void Parent(GameObject parent) { 10 this.transform.parent = parent.transform; 11 } 12 public void Parent(Transform parent) { 13 this.transform.parent = parent; 14 } 15}

set, get以上の機能があれば関数の実装で何の気持ち悪さもないのですが,
set, get以上の機能が今のところないので,関数の実装だと少し気持ち悪く感じます.
プロパティで解決できるならそうしたいと思っています.
詳しい方,ご教授お願いします.

バージョン

  • Unity 2020.3.13f1
  • .NET 4.x

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

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

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

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

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

Zuishin

2021/09/22 03:46

じゃあこれ。 これもブログや Qiita に書いたりせず、自分だけで使ってください。 気持ち悪いので。 namespace ConsoleApp1 { class GameObject { } class Transform { public GameObject Parent { get; set; } } class GameObjectFromTransform { public GameObject GameObject { get; private set; } public GameObjectFromTransform(GameObject gameObject) { GameObject = gameObject; } public GameObjectFromTransform(Transform transform) : this(transform.Parent) { } public static implicit operator GameObjectFromTransform(GameObject gameObject) { return new GameObjectFromTransform(gameObject); } public static implicit operator GameObject(GameObjectFromTransform gameObjectFromTransform) { return gameObjectFromTransform.GameObject; } public static implicit operator GameObjectFromTransform(Transform transform) { return new GameObjectFromTransform(transform); } } class BaseClass { public GameObjectFromTransform Parent { get; set; } } class Program { static void Main() { var baseClass = new BaseClass(); baseClass.Parent = new GameObject(); baseClass.Parent = new Transform(); GameObject parent = baseClass.Parent; } } }
guest

回答1

0

ベストアンサー

そもそも GameObject と Transform がどちらも Parent という名前なのはややこしいです。
どうしてもプロパティにしたいなら、そのプロパティがどこへアクセスしているのか分かるように名前を付けるべきです。

C#

1public class BaseClass : MonoBehaviour { 2 public GameObject ParentGameObject => transform.parent?.gameObject; 3 public Transform ParentTransform { 4 get { return transform.parent; } 5 set { transform.parent = value; } 6 } 7}

parentがtransformからアクセスしないといけないことがHierarchyの見た目との直感に反する

Hierarchy とソースコードは同じものではないので無理に合わせる方が直感に反するという考え方もあります。

下記の観点からプロパティを作らない方がシンプルな実装になるかもしれません。

  • そもそも transform.parent と書く事が頻繁にあるのか(ないならローカル変数で十分では)
  • 頻繁にあるとしたらコードが重複していないのか(重複しているならそれを改善すべきでは)
  • プロパティではなくローカル変数で十分でないか(十分ならプロパティはいらないのでは)

暗黒のソースコード

無理やりまとめてみましたが参考にはしないでください。

C#

1using UnityEngine; 2 3public class BaseClass : MonoBehaviour { 4 public Object Parent { 5 get { return transform.parent.gameObject; } 6 set { 7 if(value is GameObject gameObject) { 8 transform.parent.gameObject = gameObject; 9 } else if(value is Transform transform) { 10 transform.parent = transform; 11 } 12 throw new NotImplementedException(); 13 } 14 } 15}

投稿2021/09/22 01:43

編集2021/09/22 02:58
BluOxy

総合スコア2663

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

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

退会済みユーザー

退会済みユーザー

2021/09/22 02:19

そのプロパティを作成する意味はありますか? 今回のモチベーションは,質問にある通り, Unityの分かりにくい仕様を意識せずにUnityを使うことです. Unityの仕様に振り回されて過去のコードを振り返ることではありません. 御記載のコードだとモチベーションは満たせません. GameObjectを受け取るプロパティは,GameObjectの直下に紐づいてそうな親要素が実はGameObject.Transform.parentじゃないとアクセスできないややこしい仕様を隠してくれます. しかし,Transformを受け取るプロパティを用意しておかないと,parentはTransformに紐づいているということを奇跡的に覚えていた未来の自分に失礼です. このふたつの要求を同時に叶えるプロパティを実装して初めて,仕様の縛りから抜け出せます.
BluOxy

2021/09/22 02:30

・GameObject.Transform.parentじゃないとアクセスできないややこしい仕様を隠す ・parentはTransformに紐づいているということ 上記の目的は1つのプロパティのみで実現しないといけませんか。 2つのプロパティに分けて定義しても transform 経由でアクセスしていることを隠蔽できますし、プロパティの中身からparent と transform が紐づいていることを確認できます。 目的を達成しているという意味では意味があるのではないでしょうか。
BluOxy

2021/09/22 02:52 編集

親を知る方法が アタッチされた GameObject 経由 か transform.parent 経由 ぐらいしかありませんからそれを分かりにくい仕様だとは思いません。忘れるかと言われたら忘れてもドキュメントを見ればすぐに思い出せる情報量なので隠蔽するまでもないでしょう。 プロパティを定義しても問題はありませんが、transform.parent.gameObject と transform.parent という階層が違う状態をどちらも Parent という名前でまとめるのは C# 的に無理があります。Zuishin さんがコメントに書いた方法で実現できるかもしれませんがそれこそ分かりにくい仕様になります。 なので、定義するなら2つに分ければ良いのではないかと思います。
退会済みユーザー

退会済みユーザー

2021/09/22 03:25 編集

>> HierarchyとScriptが同じものではない いや,どちらもUnityの機能なので同じ意識で開発できるほうが良いでしょ. 僕は個人でやってます. >> そもそも transform.parent と書く事が頻繁にあるのか あるから実装してますし,僕にはまだ未来60年くらいあります. >> 頻繁にあるとしたらコードが重複していないのか 毎回同じように,なんでGameObjectからparent取得できひんねんと思ってるから実装します. >> プロパティではなくローカル変数で十分でないか BaseClass.GameObject.Transform.parentとBaseClass.parentが同時に値を保持することになりますが, GameObjectとTransformを同一名でどちらを渡すか意識せずに使えるならそれでもいいと思います. >> parentはTransformに紐づいているということ 恐らく伝わっていないのだと思いますが, BaseClass.Parent = newParent(GameObject) を用意して BaseClass.Parent = newParent.Transform(Transform) を用意していないと, 用意していないことをわざわざ確認して, BaseClass.GameObject.Transform.parent = newParent.Transform or BaseClasee.Parent.Transform = newParent.Transform とすることになります. これはUnityの仕様と自分の実装に振り回されています. >> 上記の目的は1つのプロパティのみで実現しないといけませんか。 GameObjectを渡すのかTransformを渡すのか,もしくは受け取るのか. それを意識しなくてもいいところで意識したくない,ややこしいから. というモチベーションです. >> C#的に無理がある 絶対に無理だというなら大丈夫です. 無理そうだなと思いつつも他の人はどうしてるんやろくらいの気持ちです. 無理な質問に答えていただきましてありがとうございます.
BluOxy

2021/09/22 04:18

> 他の人はどうしてるんやろ 私なら恐らく上記回答のように済ませると思います。 階層の違う状態 (x.y と x.y.z) を同一名でどちらを渡すか意識せずに使おうと考えたことはありません。 階層が同じでそれ等が継承関係にあるならポリモーフィズムが使えるかもしれません。 > どちらもUnityの機能なので同じ意識で開発できるほうが良い 厳密には違うものを上記のようにまとめてしまうと今回の問題のようにどこかで矛盾が生じますので、私はそうしない方が良いと思います。
fana

2021/09/22 05:42 編集

> 他の人はどうしてるんやろ もしも「C#でプロパティのオーバーロード(ができないんだけど)」みたいな枠組みの話をしたいのだとすれば, 相応に一般化した形の話にした方が意見が集まりやすいのではないかな,…とか,ちょっと思いました. なんか現状,Unity 固有の GameObjectとTransformがどうのいう特定目的に特化した話題になっている感なので,そいつらの関係性(?)とかを知らない者には話自体がなんのこっちゃわからないので. (Unity知らない私からすれば,getの際は Transform なる物の存在を隠蔽したい?のに,他方,setの側では Transform なる物を生で扱いたい?という,一体何を隠蔽したいのか謎な状態にしか見えない)
退会済みユーザー

退会済みユーザー

2021/09/22 06:25

> fana様: コメントありがとうございます. >> 一般化した形の話にした方が意見が集まりやすいのではないか 正直,詳しく意見を聞きたいのはゴリゴリにUnityを使い倒してる人です. C#の話,プログラミングの機能の話に一般化しないのは,Unity以外で使うC#に興味ないからです. それでもC#のタグをつけているのはシンプルにプロパティの機能を見逃している可能性があったからです. C#を愛している方々には失礼な質問だったかもしれません. Unityを使っている人とこういうとこ使いにくいですよねとか話できるかなくらいの気持ちでした. わざわざ回答に努めようとしてくださったUnityを知らないC#erの方々は申し訳ありません.
Zuishin

2021/09/22 06:36 編集

そもそも transform.parent の型は GameObject ではなく Transform なので、質問者がヒエラルキーについて何か思い違いをしていて、親でないものを親と思っているという前提があります。 ヒエラルキーを形成しているのは 位置や回転などを表す Transform で、GameObject はそのうち一つの Transform と紐付けられているにすぎません。 Unity を使っている人は transform.parent と書けば済むところを、わざわざ使いにくいラッパーを書いて複雑化することはないでしょう。
fana

2021/09/22 06:56

> 正直,詳しく意見を聞きたいのはゴリゴリにUnityを使い倒してる人です. なるほど.そういう雰囲気がタイトルや質問文にもっと出ていると良いのかもですね. 逆にUnityな人の目に「C#のなんだか面倒そうな話」みたく見えてしまっている可能性もありそうに思うので. (じゃあどう書けば良いのか?っていう具体的な考えみたいなのがあるわけではないのですが) 以上,横から失礼しました.
退会済みユーザー

退会済みユーザー

2021/09/22 07:15

> fana様: 質問に対するご意見ありがとうございます. 回答者様たちから僕の質問がどう見えているのかわからないので,参考になります. 次回以降質問することがあれば活かさせていただきます.
Zuishin

2021/09/22 07:20

C# のなんだか面倒そうな話以外の何物でもないと思うんですけどねえ。 正直、「ゴリゴリに Unity を使い倒してる人」も、誰もやらないような気持ちの悪いオレオレ設計に頑なに執着して、言語的解決以外聞く耳持たない質問者に言うことは何もないでしょう。
fiveHundred

2021/09/22 07:51

Unityスコア上位(Unity上級者とは言っていない)ですが、Zuishinさんの以下のコメントに同感します。 > そもそも transform.parent の型は GameObject ではなく Transform なので、質問者がヒエラルキーについて何か思い違いをしていて、親でないものを親と思っているという前提があります。 > > ヒエラルキーを形成しているのは 位置や回転などを表す Transform で、GameObject はそのうち一つの Transform と紐付けられているにすぎません。 > > Unity を使っている人は transform.parent と書けば済むところを、わざわざ使いにくいラッパーを書いて複雑化することはないでしょう。 補足しておくと、Unityの親子関係はTransformと密接に関係しており、親のtransformを動かすと、それに応じて子のtransformも動きます。 (transform.positionでやってみると分かりやすいでしょう) そう考えると、親子関係は(gameObjectよりも)transformにあるべきだと考えたほうがむしろ自然でしょう。 それをMonoBehaviorから直接出来るようにしたところで、書く際に数文字分ケチれるだけで、あまりメリットは感じられません。 過去には「GetComponentInChildren()やGetComponentInParent()が無いので拡張しよう」という意見も見られましたが、現在ではこれらは標準で用意されてますし、拡張せずともMonoBehaviorの機能で十分だと思います。
退会済みユーザー

退会済みユーザー

2021/09/22 08:04

> fiveHundred様: コメントありがとうございます. 公式ドキュメント(https://docs.unity3d.com/Manual/Hierarchy.html)の, 『The Hierarchy window displays every GameObject in a Scene』 の部分のみ読んでいました. 同ページ 『Child GameObjects inherit the movement and rotation of the parent GameObject. To learn more about this, see documentation on the Transform component .』 の部分まで読むと,僕がLearn lessだと気づきました. Editor Menu > GameObject から生成すると同時にHierarchyに追加される点, Hierarchy > 右クリックメニュー 内がGameObjectメニューと同じように見える点, Hierarchy > オブジェクト左クリック > Inspector 内に Transformの項目がある点. 以上からHierarchyにはGameObjectがあるものだと思っていました. 勉強になります,ありがとうございます.
BluOxy

2021/09/23 06:45 編集

質問が閉じられた後になりますが、もし Unity に詳しい人へ何かを聞きたいのでしたら下記のフォーラムで聞くと良そさうです(今回の件が Unity の話なのか C# の話なのかは置いておいて) https://answers.unity.com/
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問