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

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

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

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

Q&A

解決済

1回答

461閲覧

C# 与えられた文字列が定義されてた列挙型に変換できない場合はnullを返したい

yukio2022

総合スコア2

C#

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

0グッド

0クリップ

投稿2023/09/29 06:24

実現したいこと

  • 与えられた文字列が定義されてた列挙型に変換できない場合はnullを返したい
  • 型パラメータ制約がEnumの場合はnull許容値でもnullが返せないのか確認したい

前提

文字列で与えられたコード(数値)を定義されている列挙型に変換する処理を書いています。
いろんな列挙型に対応する必要があるのでジェネリックメソッドを定義しています。
戻り値がnull許容値型ならdefaultでnullが返るものだと思っていたんですが、列挙型は0で返ってしまいます。
列挙型の値に0を定義しているものがあり、これではまずいのでどうしてもnullで返したいです。
戻り値nullはそもそも書けなくてどうしたらいいんだって感じです。

該当のソースコード

C#

1namespace Main; 2 3class Program 4{ 5 public static void Main() 6 { 7 var fruitsList = new List<Fruits?>(); 8 for(var i = 0; i < 10; i++) 9 { 10 fruitsList.Add(GetEnum<Fruits>(i.ToString())); 11 } 12 13 var nameList = new List<Name?>(); 14 for (var i = 0; i < 10; i++) 15 { 16 nameList.Add(GetEnum<Name>(i.ToString())); 17 } 18 19 var fruitsList2 = new List<Fruits?>(); 20 for (var i = 0; i < 10; i++) 21 { 22 fruitsList2.Add(GetStruct<Fruits>(i.ToString())); 23 } 24 25 var nameList2 = new List<Name?>(); 26 for (var i = 0; i < 10; i++) 27 { 28 nameList2.Add(GetStruct<Name>(i.ToString())); 29 } 30 31 var dates = new List<DateTime?>(); 32 for (var i = 0; i < 10; i++) 33 { 34 dates.Add(GetStruct<DateTime>(i.ToString())); 35 } 36 37 } 38 39 enum Fruits 40 { 41 Apple = 0, 42 Banana, 43 Orange, 44 } 45 46 enum Name 47 { 48 John = 1, 49 Mike, 50 Kate, 51 Jully 52 } 53 54 // 数値の文字列をT型に変換する 55 public static T? GetEnum<T>(string? s) where T : Enum 56 { 57 if(int.TryParse(s, out var value)) 58 { 59 var temp = (T)(object)value; 60 61 if(Enum.IsDefined(typeof(T), temp)) 62 { 63 return temp; 64 } 65 66 } 67 68 return default; 69 } 70 71 // 数値の文字列をT型に変換する 72 public static T? GetStruct<T>(string? s) where T : struct 73 { 74 Type type = typeof(T); 75 if (!type.IsEnum) throw new ArgumentException(nameof(T)); 76 77 if (int.TryParse(s, out var value)) 78 { 79 var temp = (T)(object)value; 80 81 if (Enum.IsDefined(typeof(T), temp)) 82 { 83 return temp; 84 } 85 86 } 87 88 return default; 89 } 90} 91 92

試したこと

あと型パラメータ制約をstructにしてnullを返す方法を見つけたんですけど、これでもいいのか見てほしいです。

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

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

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

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

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

KOZ6.0

2023/09/29 07:15

public enum Hoge1 : long, public enum Hoge2 : ulong とか定義できるので、int.TryParse のところは long.TryParse でだめなら ulong.TryParse という感じにするといいと思います。 あと、[Flags] はどう扱うのか気になります。
KOZ6.0

2023/09/29 07:42

>int.TryParse のところは long.TryParse ~ あ! Enum.TryParse(type, s, out var value) でよかったみたいです。
KOZ6.0

2023/09/29 08:03 編集

string? が使えるということは、.NET 系だと思いますが、バージョンによって回答が変わるかもしれないので、明記してください。
yukio2022

2023/10/02 01:37

>int.TryParse のところは int.TryParseメソッドは数値に変換できたら何でもいいと思って使ってます。 >[Flags]はどう扱うのか 聞かれている内容がピンと来ていないんですけどビットフィールドのことは管変えていません。 >Enum.TryParse(type, s, out var value) でよかったみたいです。 Enum.TryParseメソッド使ってみたですんけど、文字列からの変換もいけるんですね。ここには書いていないんですけど、受け付けるコードは数値の文字列のみという仕様なのでダメみたいです。
KOZ6.0

2023/10/02 02:27

enum に使えるのは SByte/Byte/Int16/UInt16/UInt32/Int32/UInt64/Int64 です。int 以外だと問題が出る可能性があります。 Flags というのは組み合わせて使うものなので(FontStyle.Regular | FontStyle.Italic) のような値は許可するのか、しないのかってことです。 数値しか許可しないのであれば、事前に数値であるかチェックしておけばいいと思います。 まぁそこまで考える必要がないのならOKです。
yukio2022

2023/10/02 07:13

列挙型をByteで定義して256を引数に与えたらおっしゃる通りエラーが出たので正規表現で数値チェックをした後にEnum.TryParseメソッドにかけるようにしました。 教えていただきありがとうございます。
guest

回答1

0

ベストアンサー

型パラメータ制約がEnumの場合はnull許容値でもnullが返せないのか確認したい

返せません。制約を where T : struct, Enum にすれば返せるようになります。

質問からは外れますが、
nullを返す実装よりは 例外スローかFruits.Unknownのようにエラーを示す値を追加したほうが良いかもしれません。

投稿2023/09/29 07:29

編集2023/09/29 07:37
hqf00342

総合スコア394

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

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

yukio2022

2023/10/02 01:22

上記の方法でnullを返すことができスッキリしました。 これは今実装している検索エンジンの話になるんですけど、リクエストパラメータはすべて文字列型なのでそれを適切なデータ型に変換するんですけど、文字列から適切に変換できない値はパラメータが指定されていないものと同じ扱いにするという仕様なのでそれをnullということにしていて、nullかそうじゃないかでSQLクエリを組み立てています。 nullが良くないというのはNullReferenceExceptionが怖いからですか? Fruits.Unknownの考えはありませんでしたが、複数のコードをカンマ区切りで指定する("0,1,2"とか)仕様があってこれを列挙型のリストに変換して、変換したリストが空かどうかでSQLクエリに条件を加える処理にしているので難しいです。 ``` if (query.PlanBags != null && query.PlanBags.Any()) { mainQueryBuilder.AppendLine(@" AND ( 1 = 0 "); foreach (var item in query.PlanBags!) { switch (item) { case BagType.TwosomeGuarantee: mainQueryBuilder.AppendLine(" OR gp.IsTwoSomeGuaranteed IN (1, 2) "); break; case BagType.NoTwosomeExtra: mainQueryBuilder.AppendLine(" OR gp.IsTwoSomeExtraCharge = 0"); break; case BagType.NoThreeBagsExtra: mainQueryBuilder.AppendLine(" OR gp.IsThreeBagsExtraCharge = 0"); break; case BagType.LimitedFourBags: mainQueryBuilder.AppendLine(" OR gp.IsFourBagLimitPlan = 1"); break; case BagType.ReservableTwosome: mainQueryBuilder.AppendLine(" OR gp.IsTwoSomeAccept = 1"); break; } } mainQueryBuilder.AppendLine(@" ) "); } ```
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問