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

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

詳細はこちら
C#

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

Unity

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

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

Q&A

解決済

1回答

3745閲覧

【Unity】【C#】NullがセットされたプロパティをIEnumberable<String>で取得したものをString.JoinしようとするとNullReferenceエラーが発生する

Y0241-N

総合スコア1066

C#

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

Unity

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

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

0グッド

0クリップ

投稿2019/12/27 04:10

前提・実現したいこと

いつもお世話になっております。

先日【【Unity】【C#】独自クラスの異なる型のすべての要素を楽に取り出して表示したい】の内容で質問させていただき、
得た回答を基にプロパティを書き出す処理を実装したのですが、タイトルに書いてあるようにNullがセットされたプロパティをReflection.PropertyInfoで取得し、Select(x => x.GetValue(a).ToString())でプロパティを文字列で抜き出したのですが、
これをString.Joinする際にエラーが発生します。

NullReferenceException: Object reference not set to an instance of an object TestCustumList+<>c__DisplayClass7_0.<Update>b__0 (System.Reflection.PropertyInfo x) (at Assets/Unity_UI_Samples-master/Assets/InfiniteScroll/TestCustumList.cs:44) System.Linq.Enumerable+SelectArrayIterator`2[TSource,TResult].MoveNext () (at <3e4da02cf86b4fc686ed0ac61bffc210>:0) System.String.Join (System.String separator, System.Collections.Generic.IEnumerable`1[T] values) (at <1f0c1ef1ad524c38bbc5536809c46b48>:0) TestCustumList.Update () (at Assets/Unity_UI_Samples-master/Assets/InfiniteScroll/TestCustumList.cs:44)

これを回避するにはどのような方法が考えられますでしょうか?
Nullをセットするな、という回答はご遠慮願います。

該当のソースコード

cs

1using System; 2using System.Linq; 3using System.Collections; 4using System.Collections.Generic; 5using System.Xml.Serialization; 6using UnityEngine; 7 8public class TestCustumList : MonoBehaviour 9{ 10 public class CustumData 11 { 12 public GameObject Value{get; set;} 13 public int Quantity{get; set;} 14 public string ProductName{get; set;} 15 } 16 public List<CustumData> ProductList; 17 18 void Start() 19 { 20 ProductList = new List<CustumData>(); 21 } 22 void Update() 23 { 24 if(Input.GetKeyDown(KeyCode.B)) 25 { 26 //CatchProduct(); 27 var t = new CustumData(){Value = null,Quantity = 1}; 28 ProductList.Add(t); 29 30 foreach(var a in ProductList) 31 { 32 var pro = a.GetType().GetProperties();//aが持つCustumDataのすべてのプロパティを列挙する 33 var i = pro.Select(x => x.GetValue(a).ToString()); 34 35 Debug.Log(i); 36 37         ↓エラー発生箇所 38 Debug.Log(string.Join("/", pro.Select(x => x.GetValue(a).ToString())));//Selectで列挙されたプロパティに対して、aのインスタンスで保持しているプロパティの値を取得し、文字列に変換してIEnumerableとして返す 39 } 40 } 41 } 42}

試したこと

そもそもなぜエラーが発生しているのかがよくわかっていません、
pro.Select(x => x.GetValue(a).ToString())自体は型を文字列で返しているので、単体で抜き出す際にはエラーが出ません。
(Debug.Log(i);の部分)
なので文字自体は存在していると思うのですが、String.Joinの際にNullになる理由が分かりません。

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

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

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

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

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

guest

回答1

0

ベストアンサー

プロパティの値がnullということはx.GetValue(a)はnullを返します。
ですので、ToStringすべきオブジェクトがnullとなりますのでNullReferenceExceptionが発生します。

回避するには3項演算子を使用するのが簡単かと思います。

C#

1Debug.Log(string.Join("/", pro.Select(x => x.GetValue(a) == null ? "null" : x.GetValue(a).ToString())));

多分、GameObjectをToStringした場合、"UnityEngine.GameObject"みたいな型の名前としか出力されないのではないかと思います。
前の質問でも書いていますが、こういった複雑なことが出てくるのであればなおさらのこと対象クラスにToStringメソッドを実装して、必要な値を出力するようにしたほうがよろしいかと思います。

投稿2019/12/27 04:26

編集2019/12/27 04:40
YAmaGNZ

総合スコア10469

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

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

Y0241-N

2019/12/27 04:47

回答ありがとうございます。何度も助けていただき、本当に助かります。 提示していただいた3項演算子を組み込む方法で表記できました。 ご指摘していただいたように、内容がかなり複雑になってきたので、一度ToStringメソッドを実装して表記する方法も試してみようと思います。 ToStringメソッドを実装することを渋っていた理由としましては、独自クラスのプロパティ数が多いほど記述が増えるのでは?という考えから短文で解決できる方法はないかを探していた次第です。 しかし、どうもこれは私の思い違いでありそうなので、しっかりと試してみようと思います。
len_souko

2019/12/27 13:40

Unityって、x?.GetValue(a)?.ToString() ?? "null"はまだ使えないんだっけ? 変数?.メソッド()は、変数がnullの場合はメソッド()を実行せずにnullを返してくれる でもって、変数a ?? 変数bは変数aがnullでない場合は変数aの値を、変数aがnullの場合は変数bの値を返すってのの組み合わせ なので、最初に書いた式はxがnullの場合はGetValue(a)以降を実行しないし、xがnullでない場合でもx.GetValue(a)がnullだった場合はToString()を実行しないので、式の結果をnullとしてくれる 途中で?.~の?の前がnull出ない場合はそのまま処理を継続していって途中でnullがあればそれ以降は処理をせずにnullと評価する で、最後までnullが出てこなかったら普通に処理するし、どこかで〇?.▽()の〇がnullとなったらnullになるので?? "null"(" "でもstring.Emptyでもいい)にすることで結果がnullになった場合のみ代替文字列を返すのでstring.joinは落ちなくなるはず
YAmaGNZ

2019/12/27 16:15

null条件演算子とかはC#8.0でしたよね? C#8.0はUnityではまだ対応していないのではないかと思います。
vo3

2019/12/28 02:38

UnityEngineのオブジェクト(GameObject等)はnullはnullではないがあるのでそこには使用しないほうがいいですが、少なくとも2018.4は.NET 4.xが使用できるのでnull条件演算子は使えますし使ってます。
YAmaGNZ

2019/12/28 02:43

そうなのですね。訂正ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問