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

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

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

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

キャスト

キャストとは、オブジェクトの型の変換が許可された場合に、明白に別の型への変換を行うプロセスのことです。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

4回答

4253閲覧

ダウンキャストの方法

elvis

総合スコア29

C#

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

キャスト

キャストとは、オブジェクトの型の変換が許可された場合に、明白に別の型への変換を行うプロセスのことです。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

1クリップ

投稿2018/11/08 17:32

###質問内容
C#のダウンキャストについてお尋ねします。
クラスのキャストは、以下の方法で出来ました。

C#

1Base b = new AnotherClass(); //ok 2AnotherClass a = (AnotherClass)b; //ok

しかし、List<T>で同じようなことをすると、
型が違うと言われエラーになります。

どのようにしたら、実現できるのでしょうか。

*環境*
◎WPF(C#) .net Frame Work 4.5
◎visual studio Community
◎windows7 64bit

仕掛中のソース

C#

1List<Base> b = new List<AnotherClass>(); //エラー 2List<AnotherClass> a = (List<AnotherClass>)b; //エラー

どうかご教示ねがいます。

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

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

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

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

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

guest

回答4

0

ベストアンサー

List<> は値の入力、出力の両方ができるため変換ができないのです。
しかし、以下のようなコードはエラーにはなりません。(共変)

cs

1IReadOnlyList<Base> b = new List<AnotherClass>();

ジェネリクスの共変性・反変性

追記

下のパターンであれば、問題ないと思います。

cs

1IReadOnlyList<Base> b = new List<AnotherClass>(); 2List<AnotherClass> c = (List<AnotherClass>)b;

多分もう気づいてると思いますが、挙げられた失敗パターンは全て Base 型インスタンスを無理やり AnotherClass 変えようとしています。

追記2

ちなみに、もし既にある List<Base>List<AnotherClass> に変えたい場合はこうすればできます。

cs

1public class Base { } 2 3public class AnotherClass : Base 4{ 5 public AnotherClass(Base b) { } 6} 7 8var baseList = new List<Base>(); 9var drivedList = baseList 10 .Select(x => new AnotherClass(x)) 11 .ToList();

投稿2018/11/08 23:09

編集2018/11/09 09:38
gaya-K

総合スコア449

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

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

elvis

2018/11/09 04:51

ご回答ありがとうございます。 お陰様で宣言はうまくできました。 ただ、それを派生クラスにキャストするときに エラーが発生します。なぜでしょうか。 //MT_ReportPlusは、MT_Reportの派生クラス。 //MT_Report→MT_ReportPlusにダウンキャストしたい。 IReadOnlyList<MT_Report> baseList = new List<MT_ReportPlus>(); baseList = DB.MT_Report.ToList(); //データ読みこみ //◎キャスト失敗1 var haseiList1 = (List<MT_ReportPlus>)baseList; //System.InvalidCastException: '型 'System.Collections //.Generic.List`1[Project1.WPF.MT_Report]' のオブジェクトを //型 'System.Collections.Generic.List`1 //[Project1.WPF.ReportList+MT_ReportPlus]' にキャストできません。' //◎キャスト失敗2 var haseiList2 = baseList.Cast<MT_ReportPlus>().ToList(); //System.InvalidCastException: '型 'Project1.WPF.MT_Report' の //オブジェクトを型 'MT_ReportPlus' にキャストできません。' //◎キャスト失敗3 var haseiList3 = baseList.Select(x => (MT_ReportPlus)x).ToList(); //System.InvalidCastException: '型 'Project1.WPF.MT_Report' の //オブジェクトを型 'MT_ReportPlus' にキャストできません。' //◎キャスト失敗4 var haseiList4 = new List<MT_ReportPlus>(baseList.Select(x => (MT_ReportPlus)x)); //System.InvalidCastException: '型 'Project1.WPF.MT_Report' の //オブジェクトを型 'MT_ReportPlus' にキャストできません。' //◎キャスト失敗5 var haseiList5 = baseList.ConvertAll<MT_ReportPlus>(x => x); //IReadOnlyListには、ConvertAllが存在せず、使えない。
elvis

2018/11/09 09:33

>多分もう気づいてると思いますが、挙げられた失敗パターンは全て Base 型インスタンスを無理やり AnotherClass 変えようとしています。 稚拙な質問に丁寧にご回答いただき、ありがとうございます。 ようやく理解できました。
elvis

2018/11/09 10:00

>ちなみに、もし既にある List<Base> を List<AnotherClass> に変えたい場合はこうすればできます。 ありがとうございます。 早速書いてみましたが、drivedListのメンバーはNullになります。 AnotherClassのコンストラクタで何か処理する必要があるのでしょうか。
gaya-K

2018/11/09 10:03

null というか Count = 0 ですよね? だとしたら baseList に何か Add が必要です。 違ったらごめんなさい。
elvis

2018/11/09 10:14

Countは0にはなりません。 List<Base>に要素が20個あり、それを上記コードでList<AnotherClass>に変えました。 すると、要素は20個のままですが、要素一つ一つの中のメンバー(今回ですと帳票名など)が、nullとなります。 出来ればひとつお聞きしたいのですが、派生クラスのコンストラクタの引数として、ベースクラスのインスタンスを渡しているのは、どのような意図からなのでしょうか。
gaya-K

2018/11/09 10:20 編集

ああ、わかりました! 提示したコードはプロパティがないのでそれでいいんですが、プロパティがある場合はコンストラクタで一つ一つ値をコピーしてください。 当然ですが派生クラスにしかないプロパティはどうにもできません。
elvis

2018/11/09 10:53

派生クラスのプロパティに、ベースクラスのインスタンスのプロパティ(コンストラクトの引数)を代入したら、動きました。最後の最後まで付き合っていただき有難うございます。感謝してます。
guest

0

こんにちは。

既に回答は出ているので蛇足ですが。
List<Base>List<Derived>にキャストできない理由を考えてみましょう。

まずは以下のように、

csharp

1List<Base> baseList = derivedList.Cast<Base>().ToList();

Derivedのリストから作ったBaseのリストがあるとします。当たり前ですけど、これは「Baseのリスト」なんです。ということは、

csharp

1baseList.Add(new Base()); // baseListにはBaseが入ります!

このbaseListDerivedのリストにキャストすると、

csharp

1List<Derived> newDerivedlist = (List<Derived>)baseList; // baseListの中にはDerivedじゃないオブジェクトが居る!

どうしてキャストが許可されないのかこれで分かると思います。

投稿2018/11/09 06:00

tamoto

総合スコア4103

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

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

elvis

2018/11/09 08:20

とてもわかり易いご回答、ありがとうございます。 また、基本的なことも理解しておらず失礼しました。
guest

0

回答欄を見ていて思ったのですが、

DB.MT_Report.ToList(); //データ読みこみ

として生成されるリストの各要素がそもそもMT_ReportPlus型ではないのではないでしょうか?

もともとMT_Reportとして生成されたインスタンスをMT_ReportPlusにキャストは出来ないかと思います。
型を調べてみてはいかがでしょうか。

投稿2018/11/09 05:21

takabosoft

総合スコア8356

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

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

elvis

2018/11/09 06:38

ご回答ありがとうございます。 ご指摘いただいたとおり、DB.MT_Report.ToList(); の各要素はMT_Report型です。 ただ派生クラスなので、下記の方法でキャストはできました。 しかしリストで同じようなことをしようとして苦戦しております。 foreachで同じことをすれば解決でしょうか。 //ダウンキャスト MT_Report r = new MT_ReportPlus(); r.帳票名 = "テスト帳票名"; MT_ReportPlus rplus = (MT_ReportPlus)r;
elvis

2018/11/09 07:45

追記です。 >MT_Reportとして生成されたインスタンスをMT_ReportPlusにキャストは出来ない ご指摘いただいた内容が、ようやく理解できました。 大変失礼しました。 DB.MT_Report.ToList();にある、MT_Report型の各要素は、 MT_Report hoge = new MT_ReportPlus();として宣言したわけではないから、 いくら派生クラスでも、ダウンキャストできないという認識で間違いないでしょうか。 理解が浅く申し訳ございません。
takabosoft

2018/11/09 09:06

そんな感じの理解であっています。ダウンキャストの基礎を振り返っていろいろ試してみるといいかと思います。
elvis

2018/11/09 09:30

基本的なことで行き詰まり情けないです。 ありがとうございました!
guest

0

List<AnotherClass>とList<Base>は全く別の型なのでキャストすることはできません。
※間違いでした。追記をご覧下さい。

対処として、
Enumerable.Cast
があります。
Linqをusingして

c#

1using System.Linq;

c#

1List<Base> b = new List<AnotherClass>().Cast<Base>().ToList();

このようにすると可能です。
内部的な処理としてはこんな感じの事をしています。

c#

1List<Base> Cast(List<AnotherClass> list) 2{ 3 List<Base> res = new List<Base>(); 4 foreach(var e in list) 5 { 6 res.Add(e as AnotherClass); 7 } 8 return res; 9}

※追記

List<AnotherClass>とList<Base>は全く別の型なのでキャストすることはできません。

と書きましたがgaya-Kさんの言う通りジェネリックの共変性・反変性による物でした。

※テストコードを追加

C#

1using System; 2using System.Linq; 3using System.Collections.Generic; 4class MT_Report { } 5class MT_ReportPlus : MT_Report { } 6class Class 7{ 8 static void Main() 9 { 10 List<MT_Report> baseList = new List<MT_ReportPlus>().Cast<MT_Report>().ToList(); 11 List<MT_ReportPlus> plusList = baseList.Cast<MT_ReportPlus>().ToList(); 12 } 13}

投稿2018/11/08 21:17

編集2018/11/09 05:31
nakajimakotaro

総合スコア90

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

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

elvis

2018/11/09 05:01

ご丁寧な回答ありがとうございます。 お陰様で宣言はうまくできました。 ただ、それを派生クラスにキャストするときに エラーが発生します。なぜでしょうか。 MT_ReportPlusは、MT_Reportの派生クラスです。 MT_Report→MT_ReportPlusにダウンキャストしたいと思います。 List<MT_Report> baseList = new List<MT_ReportPlus>().Cast<MT_Report>().ToList(); baseList = DB.MT_Report.ToList(); //データ読みこみ このあと、List<MT_ReportPlus>にキャストするとエラー発生。 お手数ですが、エラー詳細はgaya-Kさんのコメント欄をご覧ください。 宜しくお願い致します。
nakajimakotaro

2018/11/09 05:31

テストコードを追加しました。 これをそちらの環境で動くか確かめてみてください。
elvis

2018/11/09 07:14

ありがとうございます。 テストコードは完動しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問