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

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

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

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

String

Stringは、ゼロ以上の文字から連続してできた文字の集合を扱うデータ型です。基本的にテキストを表すために使われます。

Q&A

3回答

1248閲覧

C#でユーザー定義のstring型を使いたい

kokorin

総合スコア73

C#

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

String

Stringは、ゼロ以上の文字から連続してできた文字の集合を扱うデータ型です。基本的にテキストを表すために使われます。

0グッド

0クリップ

投稿2022/02/20 02:45

シチュエーションとしては、
string型をstring型ではない別の型として定義することで実装ミスに事前に気づけるようにしたいです。

例えば、string型でif文の判定をする場合、

C#

1string item = "book"; 2int price; 3 4if (item == "book") { 5 price = 100; 6} else { ... }

のように書くかと思いますが、
string型だと他のどんなstring型でも比較できてしまうことで不具合につながるので、悩みどころです。

C#

1string userName = "John"; 2int price; 3if (userName = "book") { // UserNameはそもそもここで比較されるべきではない 4 price = 100 5} else { ... }

これを、string型をラップ?するようなMyString型があれば、

C#

1MyItemString item = "book"; 2string userName = "John"; 3int price; 4 5if (item == (MyItemString)"book") { 6 price = 100; 7} else if (userName == (MyItemString)"book") { // 型が違うためコンパイルエラーになる 8 price = 200; 9} else { ... }

のようにコンパイルエラーとしてビルド時に間違いに気づくことができるかと思います。

【質問】

  1. ユーザー定義のstring型を作成することはできますか?
    また、できる場合はその方法をお教え頂けるとありがたいです。
  2. 上記のようなstringの比較の実装ミスによる不具合を防ぐ別の方法はありますか?
    できれば、ユーザー定義型のstringとして扱いたいですが、より良い方法があればご教授いただきたいです。

以上、皆さんのお知恵をお貸しいただければ嬉しいです。

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

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

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

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

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

m.ts10806

2022/02/20 02:52

あまりメリットのあるこのをやろうとしてるようには見えないのですが(大事なのは変数が保持している情報そのものだと思うので)、実装も例ではなく具体的な要件のほうが良いかと思います。 >stringの比較の実装ミス ここが他者にはイメージ伝わりにくいのではと。
Zuishin

2022/02/20 03:00

enum を使うか、if の代わりに switch 式を使えば良いと思います。
退会済みユーザー

退会済みユーザー

2022/02/20 03:30 編集

インターンプールというのがあるのをご存じですか? 文字列を key に、ヒープ上の String オブジェクトのアドレスを value に持つハッシュテーブルのようなものです。コードに "John" と書くとコンパイルされる時にそれはインターンプールに置かれます。なので、質問者さんが書いたようなコード (MyItemString)"book" のようなことをするのは不可能かと思います。
kokorin

2022/02/20 04:09

@m.ts10806 > あまりメリットのあるこのをやろうとしてるようには見えないのですが 具体的にどのような理由でメリットがないと感じられましたか? コンパイル時点で実装ミスに気づけるという意味で十分メリットがあると考えています。 > 大事なのは変数が保持している情報そのものだと思うので こちらに関しては自分も同意です。ただ、「型」にも情報が含まれており、変数+型含めての情報ですよね? 変数に入っている情報のみでプログラムが構成できるのであれば、クラスを始めとするユーザー定義型は必要ないはずですし @Zuishin 質問の書き方が悪かったためか、意図が伝わっておらず申し訳ございません。 enum/if/switch式による実装がどうこうという意味ではなく、string型をそのまま使うことで他のあらゆるstringと比較されうるということに危険性があり、それを解消したいということです。 @SurferOnWww インターンプールというのは知りませんでした。 stringの場合に使用される保存領域ということですかね。 > コードに "John" と書くとコンパイルされる時にそれはインターンプールに置かれます。なので、質問者さんが書いたようなコード (MyItemString)"book" のようなことをするのは不可能 stringがインターンプールに置かれるので、不可能ということですが、理由と結論の間にギャップがあり理解できませんでした。 (MyItemString)"book"のようにキャストすることが無理ということでしょうか? それとも、そもそもstringから派生させたようなユーザー定義のstring型を作成することが無理ということでしょうか?
退会済みユーザー

退会済みユーザー

2022/02/20 04:50

> インターンプールというのは知りませんでした。 String Intern などをキーワードにググって調べるなどして勉強してください。 > (MyItemString)"book"のようにキャストすることが無理ということでしょうか? 何故そういうことができると思うのか分かりません。ご自分でやってみて、もし出来たら、どのようにしたのか逆に教えてもらえませんか?
Zuishin

2022/02/20 05:11

TypeScript の共用体型のようなものをお望みでしょうか? https://js.studio-kingdom.com/typescript/handbook/advanced_types#union_types それなら、将来のバージョンで入る計画はありますが、今のところはできません。 enum を使用するのが最も近いと思います。 > (MyItemString)"book"のようにキャストすることが無理ということでしょうか? 演算子のオーバーロードを使えばできなくはありませんが、それで問題が解決するかは疑問です。
退会済みユーザー

退会済みユーザー

2022/02/20 06:21

> 演算子のオーバーロードを使えばできなくはありませんが そうですね、前言「何故そういうことができると思うのか分かりません」は取り消します。失礼しました。
fana

2022/02/21 01:34

> string型だと他のどんなstring型でも比較できてしまうことで不具合につながる この話の意味がわからないです… あるデータAの内部表現(っていうか)が文字列であってそれをstringとして実装し, Aとは別の意味合いのデータBの内部表現もまた文字列であってstringとして実装したとき, AとBは全く異なる概念であるから「AとBを比較する」というのは「話の上では異常事態」なのだけどもコード的に(型的に)は問題ないのがなんか嫌だ …的な話なのでしょうか? (もしもそういう話なら,AもBもstring丸出しで実装しなければ良いというだけなのでは…? 内部表現がstringたることがmustだとして,それを抱えている型を適当に用意するのではダメなのか?)
guest

回答3

0

値オブジェクトが、質問者さんが望んでいるものに近いように見えます。組み込みの値型をラップした独自の型を、ドメイン駆動設計では値オブジェクトと呼んでいます。

値オブジェクトを導入すると次のようなコードになります。"book"や"john"のようなリテラルの代わりに、独自で定義したItemとUserを利用します。

c#

1/// <summary>Itemの値オブジェクト。nameのgetプロパティを持つ。</summary> 2record Item(string name) { } 3 4/// <summary>Userの値オブジェクト。nameのgetプロパティを持つ。</summary> 5record User(string name) { } 6 7private int GetPrice(Item item, User user) { 8 var book = new Item("book"); 9 var john = new User("john"); 10 11 int price; 12 13 // 値オブジェクトは、値としてふるまうので比較可能。 14 if (item == book) { 15 price = 100; 16 } 17 // 型が違うためコンパイルエラーになる。 18 else if (user == book) { 19 price = 200; 20 } 21 else { 22 price = 300; 23 } 24 25 return price; 26} 27 28void Main() { 29 var video = new Item("video"); 30 var john = new User("john"); 31 var price = GetPrice(video, john); 32 33 Console.WriteLine(price); 34}

値オブジェクトにはC# 9.0で導入されたrecord型を使いました。従来のclass構文と比べてコード量がかなり減ります。

参考

投稿2022/02/20 06:23

編集2022/02/20 06:24
jhashimoto

総合スコア838

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

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

0

UnitGeneratorを使えば任意の型をベースにした独自型を簡易に生成できて便利。
https://github.com/Cysharp/UnitGenerator

蛇足ですが、F#では組み込みのtypeを使って比較演算子等が揃った独自型を生成できたりします。(私はF#使わないけど、いろんな言語で広く必要とされてるパターンなんだ、という温度感を共有したい感じ)
https://bleis-tift.hatenablog.com/entry/20111201/1322728455

投稿2022/02/20 07:18

tor4kichi

総合スコア763

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

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

0

C#

1class Item{ 2//...適宜実装 3}

みたいな型を定義して

C#

1var item = new Item("book"); 2if("hoge" == item){}//error CS0019: Operator `==' cannot be applied to operands of type `string' and `Item'

C#

1class Item{ 2 public string Name{get;} 3 public Item(string name){ 4 Name = name; 5 } 6 public static explicit operator Item(string s) => new Item(s); 7 // ... 等値比較など適宜実装 8}

C#

1if("hoge" == (Item)"hoge"){} //error

投稿2022/02/20 03:38

編集2022/02/20 04:59
ozwk

総合スコア13521

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

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

kokorin

2022/02/20 04:22

普通に考えるとそうなりますよね。 しかし、比較用の定数に毎回newするのは非効率かと思いまして、 ``` var item = new Item("book"); if (new Item("hoge") == item) { } // 比較用の変数は毎回new Item()が必要 ``` new しなくても良い値型(string)を自分で定義できないかを探っていました。 classで実装するのが結局のところ、実現可能性も高く扱いもしやすそうですが。。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問