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

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

詳細はこちら
C#

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

Q&A

解決済

1回答

1485閲覧

interfaceを実装した構造体を型引数としたIEnumerable<T>型の変数に代入できない理由

mamyonya768

総合スコア4

C#

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

0グッド

0クリップ

投稿2021/01/23 21:06

編集2021/01/24 05:03

下記のTest()で、
IDataを実装するDataを型引数としたIEnumerable<Data>型をIEnumerable<IData>型に代入できないのはどうしてでしょうか?

Dataがクラスであればコンパイルが通りますが、下記のコードのように構造体の場合はエラーとなるのはなぜでしょうか?
おそらく、構造体は値型でinterfaceは参照ということが原因かと思いますが、
Test2()のようにIData型の変数にDataを代入するのは可能で、IEnumerable<IData>IEnumerable<Data>を代入するのは不可能という点が理解できません。

何卒、よろしくお願いいたします。

cs

1 public interface IData 2 { 3 } 4 public struct Data :IData 5 { 6 } 7 public class Hoge 8 { 9 public void Test() 10 { 11 IEnumerable<IData> datas = Enumerable.Range(0, 1).Select(i => new Data()); 12 } 13 public void Test2() 14 { 15 IData data = new Data(); 16 } 17 } 18

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

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

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

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

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

m.ts10806

2021/01/23 21:59

Data とIDataは型としては別じゃないでしょうか。
退会済みユーザー

退会済みユーザー

2021/01/24 02:06 編集

IEnumerable<Data> は Data がクラス(IData を継承)なら IEnumerable<IData> 型の変数に代入できるが、Data が構造体の場合はエラーになる。その理由が知りたいということですか?
mamyonya768

2021/01/24 04:48

はい、その理由を知りたく思っています。 わかりにくいためもう少し質問文を整理します。ありがとうございます。
退会済みユーザー

退会済みユーザー

2021/01/24 05:50

そもそも、 IEnumerable<IData> datas = Enumerable.Range(0, 1).Select(i => new Data()); が Data がクラス or 構造体にかかわらずダメっぽいです。Data がクラスならコンパイルも通って実行もできますが中身が空になるはずです。gentaro さんの回答のコードも中身は空になるはずです。
退会済みユーザー

退会済みユーザー

2021/01/24 06:41 編集

空ではなくて、Range(0, 1) なので 0 から始まる 1 要素は取れますね。間違ったコメントですみません。
guest

回答1

0

ベストアンサー

質問修正を受けての回答

おそらく、構造体は値型でinterfaceは参照ということが原因かと思いますが、

Test2()のようにIData型の変数にDataを代入するのは可能で、IEnumerable<IData>にIEnumerable<Data>を代入するのは不可能という点が理解できません。

要するに「共変性がstructで使えない理由は何か」という質問だということかな。

共変性と反変性 (C#)
ジェネリック インターフェイスの変性 (C#)

本質的にはこれと同じ質問内容なんでしょう。

Why covariance and contravariance do not support value type - stackoverflow

回答も書いてあるんで読んでください。

また、回答で触れられているブログのリンクが切れてますが、これが同じ内容の記事だと思う。
Representation and identity - Eric Lippert's blog

まとめると「値型は共変性がサポートされてないから。理由を知りたいなら上記を読んでくれ」という回答になります。


(元の回答)

宣言とEnumerable.Rangeの戻り値の型が合わないだけじゃないの。

diff

1 public interface IData 2 { 3 } 4 public struct Data :IData 5 { 6 } 7 public class Hoge 8 { 9 public void Test() 10 { 11- IEnumerable<IData> datas = Enumerable.Range(0, 1).Select(i => new Data()); 12+ IEnumerable<IData> datas = Enumerable.Range(0, 1).Select(i => (IData)new Data()); 13 } 14 } 15

投稿2021/01/23 21:33

編集2021/01/24 06:05
gentaro

総合スコア8947

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

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

mamyonya768

2021/01/24 04:59

回答ありがとうございます。 質問文がわかりにくかったので修正しました。
退会済みユーザー

退会済みユーザー

2021/01/24 05:51

> IEnumerable<IData> datas = Enumerable.Range(0, 1).Select(i => (IData)new Data()); それでは datas の中身が空になりませんか?
退会済みユーザー

退会済みユーザー

2021/01/24 06:39

空ではなくて 1 要素は取れますね。間違ったコメントですみません。
退会済みユーザー

退会済みユーザー

2021/01/24 07:39

Microsoft の文書を見つけました。これですね。 ジェネリックの共変性と反変性 https://docs.microsoft.com/ja-jp/dotnet/standard/generics/covariance-and-contravariance "変性が適用されるのは参照型のみです。バリアント型パラメーターに対して値型を指定すると、その型パラメーターが、結果の構築型で不変になります" (正直知りませんでした。おかげさまでまた一つ利口になりました)
mamyonya768

2021/01/24 07:56

値型はジェネリックの共変性がサポートされていないんですね。 再度回答してくだりありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問