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

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

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

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

Q&A

解決済

5回答

196閲覧

キャストの安全性と型変換について

WEjpon

総合スコア88

C#

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

0グッド

2クリップ

投稿2018/10/30 00:32

<前提>
疑問点をどのような言葉で表現してよいかわからず、タイトルと内容が合っていないかもしれません。
また、質問の書き方もおかしいかもしれません。

<やりたいこと>
複数の子クラスのいずれか1つのオブジェクトを保持するため親クラスオブジェクトを用意する。
親クラスオブジェクトのメソッドを使うときは必ず子クラスにキャストしてから使う。

<質問>(2つあります)

質問1:やりたいことを実現するため、下記コードを考えましたが問題ないでしょうか。

C#

1 public partial class Form1 : Form 2 { 3 int childType = 1; 4 cParent cp; 5 6 public Form1() 7 { 8 InitializeComponent(); 9 } 10 11 private void button1_Click(object sender, EventArgs e) 12 { 13 if (childType == 1) 14 { 15 cp = new cChild1(); // ① 16 int c1 = ((cChild1)cp).GetC(); // ②-1 17 ((cChild1)cp).Dispose(); // ②-2 18 } 19 else 20 { 21 cp = new cChild2(); 22 int c2 = ((cChild2)cp).GetC(); 23 ((cChild2)cp).Dispose(); 24 } 25 } 26 } 27 28 public class cParent 29 { 30 } 31 32 public class cChild1 : cParent, IDisposable 33 { 34 private int c1 = 10; 35 36 public int GetC() 37 { 38 return c1; 39 } 40 41 public void Dispose() 42 { 43 // ここでは何もしないが、実際は正しく実装されているものとする。 44 } 45 46 } 47 48 public class cChild2 : cParent, IDisposable 49 { 50 private int c2 = 20; 51 52 public int GetC() 53 { 54 return c2; 55 } 56 57 public void Dispose() 58 { 59 // ここでは何もしないが、実際は正しく実装されているものとする。 60 } 61 }

質問2:button1_Clickではif文でキャスト判断していますが、できれば型自体を保持しておき、
型がcTypeに入っているとして下記のようなコードでif文を無くすことはできないでしょうか。

C#

1cp = new cType(); // ① 2int c1 = ((cType)cp).GetC(); // ②-1 3((cType)cp).Dispose(); // ②-2

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

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

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

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

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

ozwk

2018/10/30 01:26 編集

本当に親クラスにGetCなどの定義は無いんですか? ライブラリ作成者がまともな思考をしていれば存在してそうなものですが。
WEjpon

2018/10/30 01:29

はい、ありません。今回は質問用にコードを書きましたが、作法に合わないことをしていたら申し訳ありません。
ozwk

2018/10/30 01:36

では、実際のコードでcp.GetC()に相当するコード書いたらコンパイルエラーになったんですね?
WEjpon

2018/10/30 01:45

いえ、コンパイルエラーにはなっていません。実行もできます。
ozwk

2018/10/30 01:58

ということは親クラスにGetC() (相当)が存在していませんか?
WEjpon

2018/10/30 02:02

はい、再度確認しましたが、存在していません。
ozwk

2018/10/30 02:17 編集

cParent型の変数cpに対して、cp.GetC()と書いてエラーにならないということは、C#の仕様上、cParent型は何らかの形でGetC()を持っているはずです。実際のコードの親クラスに更に親が存在していたり、親がpartialであったり、cChildXのGetCにあたるメソッドの定義にoverrideとかついてません?
WEjpon

2018/10/30 02:28

はい、それは理解できます。読み返していて思いましたが、10:36の記載を私が誤解したかもしれません。「cp.GetC()」というコードはご指摘の通りコンパイルエラーになります。しかし、「 ((cChild1)cp).GetC()」というコードはコンパイルエラーになりません。私はこれを「cp.GetC()に相当するコード」と解釈しておりました。
guest

回答5

0

ベストアンサー

どこの誰が作ったのか知りませんが、本当だとしたらウンコード・マニアに投稿できるくらいのウンコードですね。
もう型が全く無意味なので dynamic を使いましょう。

if 文は消しましたが、childType がどんな値でも取ることができ、1 以外は cChild2 になるという仕様なら、どのみちどこかで書かなきゃいけないんじゃないでしょうか。
可能なら enum や配列を使ってください。

C#

1using System; 2using System.Windows.Forms; 3 4namespace WindowsFormsApp1 5{ 6 public partial class Form1 : Form 7 { 8 dynamic cp; 9 Type childType = typeof(cChild1); 10 11 public Form1() 12 { 13 InitializeComponent(); 14 } 15 16 private void button1_Click(object sender, EventArgs e) 17 { 18 cp = Activator.CreateInstance(childType); 19 MessageBox.Show(cp.GetC().ToString()); 20 cp.Dispose(); 21 } 22 } 23 24 public class cParent 25 { 26 } 27 28 public class cChild1 : cParent, IDisposable 29 { 30 private int c1 = 10; 31 32 public int GetC() 33 { 34 return c1; 35 } 36 37 public void Dispose() 38 { 39 // ここでは何もしないが、実際は正しく実装されているものとする。 40 } 41 42 } 43 44 public class cChild2 : cParent, IDisposable 45 { 46 private int c2 = 20; 47 48 public int GetC() 49 { 50 return c2; 51 } 52 53 public void Dispose() 54 { 55 // ここでは何もしないが、実際は正しく実装されているものとする。 56 } 57 } 58}

投稿2018/10/30 02:04

編集2018/10/30 02:13
Zuishin

総合スコア28656

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

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

WEjpon

2018/10/30 02:21

enum や配列を使えばできそうでしたが、自分の知らないスマートな方法がないかと思い質問させていただきました。どうやらなさそうですので、enumで行おうと思います。
Zuishin

2018/10/30 02:23

このコードを見た限りなので、100% の互換性があるのはやはり if 文や三項演算子になります。 もっと条件が狭いなら別のやり方があります。
guest

0

1.適切にキャストするなら問題はないです
2.is演算子とか、asによるキャストとか、型を判別する方法はいろいろあります。

んで、通常のクラスなら、Disposeを呼ぶ必要はありません

投稿2018/10/30 00:41

y_waiwai

総合スコア87719

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

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

WEjpon

2018/10/30 01:21

回答ありがとうございます。 2について、型判別を省略したいと考えています。 イメージでいうと、キャストを使う場合は最初の質問文に示したコード、asを使う場合は下記のようなコードでしたいと考えています。 ```C# string s1 =""; Type tp = s1.GetType(); object o1 = "obj"; string s2 = o1 as tp; ```
y_waiwai

2018/10/30 01:52 編集

asでは型が違ってたらnullを返すのでそれ見てなんかすればいいかと。
WEjpon

2018/10/30 01:59

私の質問方法が不適切なのだと思いますが、やりたいこととしては質問1のコードのbutton1_Click()からif文をなくしたいです(三項演算子も)。実際はcChild1~7まであり、同じようなコードが続くからです。 asを使う方法だとif文等を使わないといけないと考えています。
y_waiwai

2018/10/30 02:04

そのコードだけではなにをしようとしてるのか見えません もちっと具体的に説明してくれないとあなたの求める回答は得られないかと。
WEjpon

2018/10/30 02:12

わかりました。未だどなたからも知りたい回答が得られておらず、私の質問方法が悪いと実感しております。
guest

0

おそらく質問1&2を見るに、以下のような事がやりたいのではないかと思いました。

charp

1using System; 2using System.Diagnostics; 3using System.Windows.Forms; 4 5namespace WindowsFormsApplication18 6{ 7 public partial class Form1 : Form 8 { 9 int childType = 1; 10 cParent cp; 11 12 public Form1() 13 { 14 InitializeComponent(); 15 } 16 17 private void button1_Click(object sender, EventArgs e) 18 { 19 if (childType == 1) 20 { 21 cp = new cChild1(); 22 } 23 else 24 { 25 cp = new cChild2(); 26 } 27 int c = cp.GetC(); 28 Debug.WriteLine(c); 29 cp.Dispose(); 30 } 31 } 32 33 public class cParent : IDisposable 34 { 35 public virtual int GetC() 36 { 37 return 0; 38 } 39 40 public virtual void Dispose() 41 { 42 43 } 44 } 45 46 public class cChild1 : cParent 47 { 48 private int c1 = 10; 49 50 public override int GetC() 51 { 52 return c1; 53 } 54 55 public override void Dispose() 56 { 57 // ここでは何もしないが、実際は正しく実装されているものとする。 58 } 59 60 } 61 62 public class cChild2 : cParent 63 { 64 private int c2 = 20; 65 66 public override int GetC() 67 { 68 return c2; 69 } 70 71 public override void Dispose() 72 { 73 // ここでは何もしないが、実際は正しく実装されているものとする。 74 } 75 } 76} 77

この辺は、「多様性」だとか「ポリモーフィズム」だとか「オーバーライド」辺りのキーワードでググってもらえれば目的の情報にたどり着けると思いますので調べてみてください。

投稿2018/10/30 00:43

takabosoft

総合スコア8356

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

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

WEjpon

2018/10/30 01:13

回答ありがとうございます。 示していただいたコードより、多様性等について理解できたつもりです。 ただ、今回に関しては言葉足らずで申し訳ございませんが、cChild1、cChild2、cParentが外部参照ライブラリ内で定義されており編集できません。そのような場合に質問2のようなことをする方法はあるでしょうか。
guest

0

正しい意図をつかめてないかもしれないので的外れであればスルーしていただいて構いません

あまりスマートではなく実行速度にも難有ですが
dynamic キーワードを用いてダックタイピング的に実装するのはどうでしょうか

Typeからインスタンスを作成するのは以下のリンクを参考にしてみてください
参考リンク

投稿2018/10/30 02:12

MMashiro

総合スコア2378

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

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

WEjpon

2018/10/30 02:18

どのように質問してよいかがわからず、再度整理してから質問する必要性を感じています。
guest

0

複数の子クラスのいずれか1つのオブジェクトを保持するため親クラスオブジェクトを用意する

…とかいう雰囲気の事柄を,cParent に頼らずに自前で用意するとか.

Csharp

1//cParentの変わり 2interface MyIF 3{ 4 int GetC(); 5} 6 7//cChild1用 8class IF_for_Child1 9{ 10 private readonly cChild1 m_Obj; 11 public IF_for_Child1( cChild1 Obj ){ m_Obj = obj; } 12 public int GetC(){ return m_obj.GetC(); } 13} 14//※cChild2用のクラスも同様に. 15class IF_for_Child2{ ... } 16 17// 18static class Factory 19{ 20 public static MyIF Create( cChild1 obj ){ return new IF_for_Child1( obj ); } 21 public static MyIF Create( cChild2 obj ){ return new IF_for_Child2( obj ); } 22}

一応,使う側の例も追記しておく.

Csharp

1MyIF X = Factory.Create( new cChild1() ); //あるいはnew cChild2 2... 3MyIF.GetC(); //cChild1(あるいはcChild2)のGetC()が呼ばれる

投稿2018/10/30 01:30

編集2018/10/30 03:25
fana

総合スコア11632

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

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

WEjpon

2018/10/30 02:31

自分の勉強不足でいただいたコードが理解できておりませんが、勉強したいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問