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

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

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

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

Q&A

解決済

4回答

7203閲覧

C#でプリミティブ型をラップしたい

super_hogehoge

総合スコア29

C#

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

0グッド

1クリップ

投稿2017/06/26 07:33

###前提・実現したいこと

C#でintやdoubleといったプリミティブ型をそのまま使わずラップしたい

void set_time(int hour, int minute, int second){...} ではなく
void set_time(Hour hour, Minute minute, Second second){...} のように
表現したい

###該当のソースコード

public class WrapperPrimitive<Type> { private readonly Type value; public WrapperPrimitive(Type value) { this.value = value; } public static explicit operator WrapperPrimitive<Type>(Type value) { return new WrapperPrimitive<Type>(value); } public static explicit operator Type(WrapperPrimitive<Type> temp) { return temp.value; } public override bool Equals(object obj) { if (obj == null) { return false; } if (this.GetType() != obj.GetType()) { return false; } WrapperPrimitive<Type> c = (WrapperPrimitive<Type>)obj; return (this.value == c.value); } //VSの補完が自動で作成 無いと警告が出るので残す public override int GetHashCode() { return base.GetHashCode(); } } public class Second: WrapperPrimitive<int> { public Second(int value) : base(value) { } }

###発生している問題・エラーメッセージ

public override bool Equals(object obj)関数のreturn (this.value == c.value);箇所で operator cannot be applied to operands of type 'Type' and 'Type'

###試したこと
https://msdn.microsoft.com/ja-jp/library/ms173147(v=vs.90).aspx
等を参考に自分なりにoperator==をオーバーロードしてみましたがうまくいきませんでした。

###補足情報(言語/FW/ツール等のバージョンなど)
いつも参考にさせていただいております。

C#初心者の為見当違いの質問でしたらお許しください。
上記案件について

・なぜうまくいかないか
・そもそもC#で型をラップするようなやり方は推奨されるのか

の2点についてご教授いただけると幸いです。
稚拙な質問でご迷惑かと思いますが宜しくお願い致します。

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

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

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

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

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

guest

回答4

0

ベストアンサー

技術者としてよくある、単に「やりたい」の回答として

csharp

1using System; 2 3namespace foo 4{ 5 public class WrapperPrimitive<Type> 6 { 7 private readonly Type value; 8 public WrapperPrimitive(Type value) { this.value = value; } 9 public static explicit operator WrapperPrimitive<Type>(Type value) { return new WrapperPrimitive<Type>(value); } 10 public static explicit operator Type(WrapperPrimitive<Type> temp) { return temp.value; } 11 12 public override bool Equals(object obj) 13 { 14 if (obj == null) { return false; } 15 if (this.GetType() != obj.GetType()) { return false; } 16 WrapperPrimitive<Type> c = (WrapperPrimitive<Type>)obj; 17 return this.value.Equals(c.value); 18 } 19 20 public static bool operator ==(WrapperPrimitive<Type> lhs, WrapperPrimitive<Type> rhs) 21 { 22 return lhs.Equals(rhs); 23 } 24 25 public static bool operator !=(WrapperPrimitive<Type> lhs, WrapperPrimitive<Type> rhs) 26 { 27 return !lhs.Equals(rhs); 28 } 29 30 //VSの補完が自動で作成 無いと警告が出るので残す 31 public override int GetHashCode() { return base.GetHashCode(); } 32 } 33 34 35 public class Second: WrapperPrimitive<int> 36 { 37 public Second(int value) : base(value) { } 38 } 39 40 class Program 41 { 42 static void Main(string[] args) 43 { 44 Second foo = new Second(1); 45 Second bar = new Second(1); 46 if (foo == bar) { 47 Console.WriteLine("Yes We Can"); 48 } 49 } 50 } 51}

投稿2017/06/26 07:58

mattn

総合スコア5030

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

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

super_hogehoge

2017/06/26 10:21

皆さん非常に丁寧に解説して下さり非常に助かりました、ありがとうございました。 甲乙つけ難かったのですが技術的な解決策を提示して下さったmattnさんをベストアンサーに 選ばせていただきました。  ありがとうございました。
guest

0

mattnさんがエラーを解消する方法について回答されていますが、追加でコメントしてみます。

intやdoubleなどのプリミティブをジェネリクスでラップしたいならしかるべき配慮を怠らないように言語仕様を注意深く調べる必要があると思います。

  • 値の同一性

GetHashCodeを「無いと警告が出るので残す」という理由で自動生成されたbase.GetHashCode()のまま放置されてますが、それはいただけません。自動生成された内容はあくまで基底クラスの動作と同じにするという内容ですが、本件では「同じ値を持つ異なるインスタンスのハッシュ値が違う値になる」という病的な結果となるため正しいとは言えません。とりあえず以下のように矛盾が生じない定義にしておく必要があると思います。

C#

1class ... { 2 public override int GetHashCode() { 3 return value.GetHashCode(); 4 } 5}

その他:

  • 型引数に対する制約

Typeには何でも指定できてしまいますがprimitive型を想定しているなら、できる限り型引数の制約を書いておいた方がよいのではないでしょうか。

C#

1class WrappedPrimitive<T> where T: struct { 2}
  • 演算子

プリミティブ型のラップ型ならば、いくつかの演算子が使えないと(C#では)不自然に感じる場合もあると思います。時、分、秒なら==, !=, <, <=, >, >=あたりはほしいのではないでしょうか?しかしながら四則演算に対して閉じてない(値域が定義域とは異なるという意味です)ので四則演算は下手に定義できない気がします。

投稿2017/06/26 09:15

KSwordOfHaste

総合スコア18392

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

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

0

operatorは、プログラミングの本をよむと書いてあるけど、ほぼ使わない。言語仕様として、ライブラリを作る上級者には必要なものだけど、そうでもないなら使わない。
汎用性のあるoperatorは難易度高い。やるなら、それぞれの型ごとに作ったほうがいいけど、ただ面倒なだけ。

はじめの問題に対応するだけなら、
適切にクラスを作ればいいだけと思います。

public class DateObject { public int Hour { get; set; } public int Minute { get; set; } public int Second { get; set; } } public void Set_Time(DateObject date) { }

呼び出し方

Set_Time(new DateObject() { Hour = 22, Minute = 12, Second = 21 });

投稿2017/06/26 07:51

kiichi54321

総合スコア1984

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

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

0

単純に型TをWrapして別名を付けると言うことはC#ではまずしないです。
恐らく、C言語あたりの#define あたりを企図してかのコトかと思いますが、C#では別名を付ける強い理由もなくまた、余計な混乱を生むだけなので行われた事例を寡聞にして知りません。

さて、立ち戻って、掲示されたコードを拝見するに、WrapperPrimitive型には元のPrimitive型の元値がどこにも保持されておらず、そもそも==のしようがないという問題があります。
また、C#においては、型引数Tに対してPrimitiveのみを受容すると言うことをコンパイルタイムに弁別することは不可能なので、名前だけになっており可否の判断以前にこのようなクラスを使うべきではないと考えます。(さらに申し上げれば、値型をわざわざオレオレBoxingする必要もありますまい)

投稿2017/06/26 07:57

Tokeiya3

総合スコア260

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問