🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

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

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

コンストラクタ

オブジェクト指向言語において、オブジェクトを生成時に呼び出され、データの初期化などを行なう関数・メソッドのことである。

Unity

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

Q&A

解決済

4回答

1283閲覧

コンストラクタによるメソッドの有効化について

suzuki0707

総合スコア1

C#

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

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

コンストラクタ

オブジェクト指向言語において、オブジェクトを生成時に呼び出され、データの初期化などを行なう関数・メソッドのことである。

Unity

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

0グッド

0クリップ

投稿2020/11/25 06:21

編集2020/11/25 07:19

前提・実現したいこと

一つのクラスでいくつかのそれぞれ違う引数をとるコンストラクタを作成し、
それに対応するメソッドを呼び出せるようにしたいのですがどのようにすればよいかわかりません。
それ以前に、これが実現可能かどうかもわかりませんので回答のほどよろしくお願いいたします。

具体的な内容

__// 修正__ public class A { private int ListSize = 5; private List<string> StrList; private List<float> FloatList; public A(){    初期化内容; } public A(string str){    // リストの中身をListSize分作成する    for(var i=0;i<ListSize;i++) StrList.add(""); } public A(float value){    // リストの中身をListSize分作成する    for(var i=0;i<ListSize;i++) FloatList.add(0); } public Method(){ A()の初期化内容を使った処理; } public Method(string str){  // 実行毎に、最新から5つのstrを保持するStrListを作成する     } public Method(float value){ // 実行毎に、最新から5つのvalueを保持するFloatListを作成する } }

具体的な内容としては、現在同じ処理をそれぞれ型の違う(Vector3/Quaternion/float)数値へかけています。
そこで処理を共通化したいのですが、処理を掛ける型分クラスを作成するのはどうかと思い上記のようなクラスを考えました。
しかし、上記の例だとA(string str)でインスタンス化し、Method(string str)のメソッドが使えれば問題はないのですが引数を間違ってMethod(float value)を実行してしまうことがあると思います。
自分だけでやっている場合にはこれでもいいかもしれませんが、多人数でこのクラスを使用する場合は問題になります。
そこで使用したコンストラクタによりメソッドが有効化されるようなことはできないのか、そもそもクラスを分けるべきなのかと思い質問させていただきました。
よろしくお願いいたします。

※追記
使用想定としては、unityでupdate()が呼ばれる毎に最新の値をListSize分常に持ちたいと考えています。

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

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

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

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

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

BluOxy

2020/11/25 06:51 編集

Aクラスのコンストラクタがどのように初期化していて、Methodがどのように処理しているかがもし書けるのであれば、より正確な回答ができます。 例えば、Automatic9045さんが回答したようにジェネリッククラスを使うことも可能かもしれないし、不可能かもしれません。
guest

回答4

0

ジェネリッククラス(ClassName<T>)を使ってみてはいかがでしょう?
インスタンス化する際に型を指定出来ます。

C#

1public class MyClass<T> 2{ 3 public MyClass(T arg) 4 { 5 ... 6 } 7 8 public void MyMethod(T arg) 9 { 10 ... 11 } 12} 13 14class MainClass 15{ 16 static void Main(string[] args) 17 { 18 MyClass<string> a = new MyClass<string>("hoge"); 19 a.MyMethod("aaa"); 20 } 21}

##追記を受けて
ジェネリッククラスを用いれば、コンストラクタの引数は不要になります。
型パラメータTの型はtypeof(T)で取得出来るので、初期化処理は以下のように書けます。

C#

1// Linqを用いると、繰り返し系の処理をfor無しで可読性高く書けます。 2// また、C#では変数名はローワーキャメルが原則なのでご注意を。 3 4public A() 5{ 6 switch (typeof(T)) 7 { 8 case typeof(string): 9 strList = new List<string>(Enumerable.Repeat(string.Empty, listSize)); 10 break; 11 ... 12 } 13}

投稿2020/11/25 06:31

編集2020/11/25 08:33
Automatic9045

総合スコア313

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

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

suzuki0707

2020/11/25 07:21

回答ありがとうございます ジェネリッククラス自体を知らなかった為、大変参考になりました。
Automatic9045

2020/11/25 07:38

ジェネリッククラスは、標準で提供されているものだとList<T>やCollection<T>、Dictionary<T>などに使われているので、良ければ調べてみて下さいね。
guest

0

ベストアンサー

A(string str)でインスタンス化し、Method(string str)のメソッドが使えれば問題はないのですが引数を間違ってMethod(float value)を実行してしまうことがあると思います。

このクラスの設計者はXMLコメントを追加してください。
このクラスの利用者はそれを読んで意図した引数をインスタンス作成時に渡してください。

VisualStudioを使っていれば、コンストラクタ呼び出しの記述にカーソルを合わせる事でXMLコメントの内容や渡している引数を見る事が出来ます。

利用者に、ドキュメントを読んで使うという意識があれば間違うことはありません。
その意識がなければ、そもそもプログラマとしてどうかを疑います。

Convertクラスを見てください。ToByteメソッド、ToBooleanメソッドなどはオーバーロードを多く行っていますが、ドキュメントを読めば引数を渡し間違うことはありません。

よって、余程疲れていない限りプログラマなら間違って使うことは無いはずなので、問題にはなりません。

suzuki0707さんがドキュメントを書き、利用者がそれを読んでも誤解をするような複雑な作りである場合はクラスを分けるなどの手段を検討すれば良いと思います。

使用したコンストラクタによりメソッドが有効化されるようなことはできないのか

言語仕様にないので出来ません。その必要がないと判断されているからです。


ジェネリックで型を指定できる最新の要素のみを保持する固定長のコレクションを用意すれば実現できませんか?

試しに作りました。

C#

1public class FixedLengthList<T> : IList<T> 2{ 3 private readonly List<T> _list; 4 private readonly int _size; 5 public FixedLengthList(int size) 6 { 7 _list = new T[size].ToList(); 8 this._size = size; 9 } 10 11 public T this[int index] 12 { 13 get => _list[index]; 14 set => _list[index] = value; 15 } 16 17 public int Count => _list.Count; 18 19 public bool IsReadOnly => ((IList<T>)_list).IsReadOnly; 20 21 public void Add(T element) 22 { 23 if (_list.Count() >= _size) 24 { 25 _list.RemoveAt(0); 26 } 27 _list.Add(element); 28 } 29 30 public void Clear() 31 { 32 _list.Clear(); 33 } 34 35 public bool Contains(T item) 36 { 37 return _list.Contains(item); 38 } 39 40 public void CopyTo(T[] array, int arrayIndex) 41 { 42 _list.CopyTo(array, arrayIndex); 43 } 44 45 public IEnumerator<T> GetEnumerator() 46 { 47 return ((IList<T>)_list).GetEnumerator(); 48 } 49 50 public int IndexOf(T item) 51 { 52 return _list.IndexOf(item); 53 } 54 55 public void Insert(int index, T item) 56 { 57 _list.Insert(index, item); 58 } 59 60 public bool Remove(T item) 61 { 62 return _list.Remove(item); 63 } 64 65 public void RemoveAt(int index) 66 { 67 _list.RemoveAt(index); 68 } 69 70 IEnumerator IEnumerable.GetEnumerator() 71 { 72 return ((IList<T>)_list).GetEnumerator(); 73 } 74}

現在同じ処理をそれぞれ型の違う(Vector3/Quaternion/float)数値へかけています。

そこで処理を共通化したい

C#

1public class A 2{ 3 private const int ListSize = 5; 4 private FixedLengthList<Vetctor3> _vectors = new FixedLengthList<Vetctor3>(ListSize); 5 private FixedLengthList<Quaternion> _quaternions = new FixedLengthList<Quaternion>(ListSize); 6 private FixedLengthList<float> _floatValues = new FixedLengthList<float>(ListSize); 7 8 public void Method(){ 9 //TODO: _vectors,_quaternions,_floatValues を参照して何かを処理する; 10 } 11 12 public AddVector3(Vector3 v){ 13 _vectors.Add(v); 14 } 15 16 public AddQuaternion(Quaternion q){ 17 _quaternions.Add(q); 18 } 19}

投稿2020/11/25 06:41

編集2020/11/25 08:28
BluOxy

総合スコア2663

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

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

suzuki0707

2020/11/25 07:25

回答ありがとうございました
BluOxy

2020/11/25 08:14 編集

> unityでupdate()が呼ばれる毎に最新の値をListSize分常に持ちたい やりたいのは(最新の要素を保持する)固定長のリストのように思います。 であれば1つのクラスに複数の型を持つのはやめ、型毎にその固定長のリストを用意すれば良いと思います。
suzuki0707

2020/11/25 12:01

再度、回答ありがとうございました。 作成例も初学者の自分自分としては知らないものもあり大変勉強になりました。
guest

0

間違った引数のMethod()を呼ばれたら例外でも投げておけばどうでしょう.

容赦なくNullReferenceExceptionが飛ぶ:

C#

1class A 2{ 3 public A(){ m_method = this.Method_; } 4 public A( string str ){ m_method_s = this.Method_s; } 5 public A( float value ){ m_method_f = this.Method_f; } 6 7 public void Method(){ m_method(); } 8 public void Method( string str ){ m_method_s(str); } 9 public void Method( float value ){ m_method_f(value); } 10 11 private readonly Action m_method = null; 12 private readonly Action<string> m_method_s = null; 13 private readonly Action<float> m_method_f = null; 14 15 private void Method_(){ Console.WriteLine( "Method()" ); } 16 private void Method_s( string str ){ Console.WriteLine( str ); } 17 private void Method_f( float value ){ Console.WriteLine( value ); } 18}

投稿2020/11/25 07:31

fana

総合スコア11985

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

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

0

ジェネリッククラスで解決できるのであればそちらを使うべきでしょうし、「間違って○○してしまう」と考えだすと何も出来なくなってしまいます。
もしどうしてもというのであれば下記のように自分でフラグを設けるなどすればいいのではないですか?

C#

1class A 2{ 3 private int mytype; 4 5 public A() 6 { 7 mytype = 0; 8 // 初期化A 9 } 10 public A(string value) 11 { 12 mytype = 1; 13 // 初期化B 14 } 15 public A(float value) 16 { 17 mytype = 2; 18 // 初期化C 19 } 20 21 public void Method() 22 { 23 if(mytype != 0) 24 { 25 throw new ArgumentException("型が違います"); 26 } 27 // 処理A 28 } 29 30 public void Method(string value) 31 { 32 if (mytype != 1) 33 { 34 throw new ArgumentException("型が違います"); 35 } 36 // 処理B 37 } 38 39 public void Method(float value) 40 { 41 if (mytype != 2) 42 { 43 throw new ArgumentException("型が違います"); 44 } 45 // 処理C 46 } 47} 48

投稿2020/11/25 07:14

YAmaGNZ

総合スコア10469

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

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

suzuki0707

2020/11/25 07:31

回答ありがとうございます。 フラグ管理を考えさせていただきたと思います
YAmaGNZ

2020/11/25 07:36

追記された内容を見るとジェネリッククラスで大丈夫のように思えます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問