c# 暗黙/明示的型変換の許容範囲

このQ&Aのポイント
  • c#初心者のための暗黙/明示的型変換の許容範囲についての質問
  • c#で暗黙/明示的型変換を定義することができるが、どの程度の変換が許容されるか疑問
  • 具体例を交えて、暗黙/明示的型変換の許容範囲について詳細を知りたい
回答を見る
  • ベストアンサー

c# 暗黙/明示的型変換の許容範囲

 こんにちは。毎度皆さんにお世話になっているc#初心者です。  c#にも暗黙/明示的型変換を定義することが出来ますよね? それで、どこまでのものが暗黙の型変換として許容されるかということが疑問になり質問させていただきました。毎度のことですがライブラリ内のクラス・構造体についてです。  例えば、あんまり意味はありませんが、百分率を表す構造体 public struct Percentage {   private int _percentage; }  があり、その内部で public static implicit operator Percentage(int value) { return new Percentage(value); }  程度なら十分許される範囲だと思います(間違っていたらご指摘ください)。  ですが、例えば、「System.Drawing.Color」構造体と同じものを作ったとして、本来「FromName」メソッドで処理するのが妥当と思われる「string」から「Color」への変換を puclic static explicit operator Color(string name) { return FromName(name); }  のようにしてしまうのはまずいのでしょうか? 多分まずいですよね。だとすると、どの程度の変換がボーダーラインなのか(出来れば具体例もあれば助かります)知りたいのですが、どなたか詳しい方はいらっしゃいませんか?

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

私の判断はどちらも不可。 まず,基本的なところ。 MSDN: 変換演算子 http://msdn.micosoft.com/ja-jp/library/ms229033.aspx 後者の例について, > 型のドメインの外部で変換演算子を定義しないでください。 に反する以上,変換演算子を「定義すべきではない」となる。 次に,前者について,本質的に百分率の値である以上,10%は0.10mと等しいはず。 さらに,intをPercentageに変換したい場合,値を保持するのか,表現を保持する(=1/100の値を保持する) のか,両方の要求が存在する。 故に,intからPercentageへの変換は明示的な名前のついたメソッドで行うべき。 # decimalへのimplicit castは必要であればあってもよい。

koumei000
質問者

お礼

 回答ありがとうございました。  よく考えてみれば、今、ボーダーラインを曖昧に知っておくよりは、今後、個別にOKかNGかの質問をするほうが理にかなっているようです。  今回はこんな初心者に付き合ってくださってありがとうございました。

koumei000
質問者

補足

 毎度毎度、回答・ご指摘ありがとうございます。 > 私の判断はどちらも不可。  そうですね。よく考えればこの前読みました。もう少しいい例を考えるべきでした。  ただ、少し、補足させてください。 > 本質的に百分率の値である以上,10%は0.10 > intをPercentageに変換したい場合,値を保持するのか,表現を保持する(=1/100の値を保持する) のか  百分率の値ではなく、百分率そのものです。前記の型変換がよいかどうかはともかく、百分率が整数であるとしたのは「System.ComponentModel.ProgressChangedEventArgs」の「ProgressPercentage」を見てください。整数型になっているはずです。  また、辞書によると 「全体を100としたとき、そのうちのいくらにあたるかということ。単位はパーセント。」  です。と言うわけで、百分率=整数と判断しました(上記の型変換がよいかどうかは別として)(間違いがあればご指摘ください)。  それともう一つ、本題のボーダーラインって分かりませんか? 曖昧かつ初歩的なな質問で苦労されるかと思いますが…。

その他の回答 (1)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

1点だけ: 百分率は (パーセントを単位としても) 整数とは限りません. そして, System.ComponentModel.ProgressChangedEventArgs において整数としているのは「そのように設計した」以上の意味を持ちません.

koumei000
質問者

お礼

 回答ありがとうございます。  そういうことだったんですね。以後気をつけます。

関連するQ&A

  • C#で独自の型を定義したい

    C# 2010 version 4.0を使用しています。 次のようなint型とstring型を混合したMixedという型を定義したいのですが、 public class Mixed { private int _TheInt = 0; public int TheInt { get { return _TheInt; } set { _TheInt = value; } } private string _TheString = null; public string TheString { get { return _TheString; } set { _TheString = value; } } public static implicit operator int(Mixed m) { return m.TheInt; } public static implicit operator Mixed(int x) { Mixed m = new Mixed(); m.TheInt = x; return m; } public static implicit operator string(Mixed m) { return m.TheString; } public static implicit operator Mixed(string x) { Mixed m = new Mixed(); m.TheString = x; return m; } } //Mixed m = 1; //Console.WriteLine(m); //これだとコンパイルエラーになる //Console.WriteLine(m.TheInt.ToString()); //「1」と表示される int i = 1; Console.WriteLine(i); //「1」と表示される object o = 1; Console.WriteLine(o); //「1」と表示される Console.WriteLineなどで表示する場合に 例えばint型なら int i = 1; Console.WriteLine(i); //「1」と表示される という具合にそのまま「1」と表示されます。 でもこのMixedの場合、 Mixed m = 1; Console.WriteLine(m.TheInt.ToString()); //「1」と表示される これでは「1」と表示されるのですが、 Console.WriteLine(m); //これだとコンパイルエラーになる このやり方だとエラーになります。 なんとかしてint型やobject型のようにToString()を使わずに 表示させることはできないでしょうか?

  • C#で構造体配列

    C#で構造体配列の操作練習?をしているのですが using System; using System.Collections.Generic; using System.Text; namespace test1 { public struct Data { public string name; // 名前 public uint value; // 値 } class read { Data[] human = new Data[300]; public static string idSearch() { for (int i = 0; i < 300; i++) { if (test1.read.human[i].value == 25) return test1.read.human[i].name; } } } } だと エラー CS0120: 静的でないフィールド、メソッド、またはプロパティ 'test1.read.human' で、オブジェクト参照が必要です。 と言うエラーが出るのですが、どうしてでしょうか?

  • C++ の map についてです

    C++の初心者です。よろしくお願いします。 DirectXを使っていて簡単なゲームを作っていまして、 mapを使っていると、このようなエラーが出てしまいどうしても理由わかりませんでした。 class D2DMap : public GameTexture{ protected: GameTexture** CopyTexture; int MaxMass; int WidthMass; int HeightMass; int WidthMassPixel; int HeightMassPixel; int MassInfo[30][30]; public: D2DMap(); virtual ~D2DMap(); HRESULT LoadMapTexture(int widthmass, int widthmasspixel,int heightmass, int heightmasspixel, const char* FileName, D3DCOLOR color); HRESULT LoadTextMass(const char* FileName); int GetWidthMassPixel(){ return WidthMassPixel;} int GetWidthMassNum(){ return WidthMass;} int GetHeightMassPixel(){ return HeightMassPixel;} int GetHeightMassNum(){ return HeightMass;} int GetMassInfo(int x, int y){ return MassInfo[y][x];} void DrawMap(D3DCOLOR color); void DrawCopyMap(D3DCOLOR color); void SetCopyTex(GameTexture* copy){ CopyTexture= &copy;} void Delete(){} }; map<string , D2DMap*> MapBox; と定義して string Name="--------"; D2DMap map; MapBox.insert( map<string, D2DMap*>::value_type(Name, &map)); としたとこと error C2275: 'std::string' : この型は演算子として使用できません 'std::string' の宣言を確認してください。 error C2059: 構文エラー : '>' error C2039: 'value_type' : '`global namespace'' のメンバではありません というエラーが出てきました。 mapのfind や iterator は可能なのですがinsertの場合エラー となり、理由が全く分かりません。詳しい方アドバイスをお願いしたい のですが、よろしくお願いします。 VC++2008 を使っています。

  • C++の問題で・・

    C++の問題で・・ 参考書に「簡易的な文字列クラスStringを作成せよ。」という問題があり作りました。 いかにそのコードを示します。今回の質問の内容に関係ないとおもうところや、インクルードなどは省かせていただきます。 環境は Visual studio 2008です。OSはXPです。 class String{     int len; //文字列の長さ     char *s; //文字列の先頭文字へのポインタ public:     String(const char *);     int length()const{return len;} //長さを求める     operator const char * ()const{return s;}     bool operator==(String &a)const{return strcmp(this->s, a);}     char *operator+(String&)const; }; char * String::operator +(String &a)const {     char *memory = new char[this->len + a.len + 1];     memory[0] = '\0';     return strcat(strcat(memory, this->s), a); } String::String(const char *p): s(const_cast<char *>(p)), len(strlen(p)){} String::String(const String &x) {     s = x.s;     len = x.len; } inline std::ostream& operator<<(std::ostream &s, String &x) {     return s << static_cast<const char *>(x); } int main() {     String a("My name is Paul");     String b("My name is Paul");     String c("My name");     String d(" is Paul");     cout << "a = " << a << "\n";     cout << "b = " << b << "\n";     cout << "c = " << c << "\n";     cout << "d = " << d << "\n";     cout << "a == b " << (a == b) << "\n";     cout << "a == c " << (a == c) << "\n";     cout << "c + d = " << (c + d) << "\n"; }     このようなプログラムなのですが、上記の char * String::operator +(String &a)const {     char *memory = new char[this->len + a.len + 1];     memory[0] = '\0';     return strcat(strcat(memory, this->s), a); } ところで、 memory[0] = '\0'; を除くと文字列を出力した結果をみると、先頭にいらない言葉が入っています。 僕の場合は x9My name is Paul と表示されます。文字化け・・ではないのですが、ゴミのようなものが・・ どうしてこのようなことが起こるか、どこでゴミが入ってしまうのか教えてほしいです。 稚拙なプログラムで申し訳ないです。 もし、間違っている場所や、もっと簡単にかけるようなところがあれば、ご指摘いただくとありがたいです。 よろしくお願いします!

  • Java 可変長引数と優先度

    Java 可変長引数と優先度  こんにちは。c#初心者兼、java始めました です。  可変長引数の場合のオーバーロードの優先度について困っています(質問と言うより半分愚痴です)。  javaにも可変長引数ってありますよね。(ジェネリックの弱さにイライラしていたけれど)「javaも捨てたものじゃない」と感心しながら使っていると、いきなりコンパイルエラー。  sampleMethod(10, 20); と書いている部分でエラーが発生していました。  自分のメソッド定義を確認しみると、  void sampleMethod(int...);  void sampleMethod(Object...);  の2種類のオーバーロードがあり、ambiguousなため判別不能らしいです。    確かに、AutoBoxingされれば、int...だけでなく、Object...にもマッチしますが、どう考えてもBoxingしない方が優先度が高いはずです。というか、高く設定されるべきです。  個人的に基準にしているc#ではこのようなことは起きませんでした。  (あ、やっぱり捨てたものかもしれない ←心変わり早す(ry )    試しにc#でInteger型のクラスを作り、(実際はタブーですが)暗黙のキャストを双方向でオーバーロードして実験してみました。   public class Integer // ここからc# {   private int _value;   //----------------------------   public Integer(int value) { _value = value; }   //----------------------------   // Integer → int の暗黙の型変換   public static implicit operator int(Integer value)   { return value._value; }   // int → Integer の暗黙の型変換   public static implicit operator Integer(int value)   { return new Integer(value); }   //----------------------------   // javaの sampleMethod(int... values)に相当   public static void SampleMethod(params int[] values) { }   // javaの sampleMethod(Object... values)に相当   public static void SampleMethod(params Object[] values) { } }  そして、Integer.SampleMethod(10, 20); と書いてみると……問題……なし。  ちゃんと、SampleMethod(param int[] values)が選ばれていました。  つまり、(個人的には)java(コンパイラ)の方が不可解な動きをしているのです。  sampleMethod(int, int)とsampleMethod(Object, Object)があるときは問題ないので、可変長引数のときだけambiguousになるようです。  「それなら」と思い、sampleMethod(int, int...)とsampleMethod(Object, Object...)を作ってみましたが、やはりエラーが出ます。  何か良い解決策はあるでしょうか?  可変長じゃない引数のオーバーロードを大量に作ることと、片方の可変長をやめること以外でアドバイスをお願いします。  もしくは、「個人的には~だから、パクリのc#よりjavaの方が動きが正しいぞ!」という方がいらっしゃいましたら、ご意見ください。

  • C#のnull許容の警告について

    「Visual Studio」のNET6.0の環境でコードを書いています。 static string UserName; という変数の宣言に対して 「null非許容のフィールドUserNameには、コンストラクターの終了時にnull以外の値が入っていなければなりません。フィールドをNULL許容として宣言することをご検討ください。」 という警告を回避するために static string? UserName; というnull条件演算子で対応したのですが、上司に 「トリッキーな方法(?)ではなく、初期化や代入を使え」 と言われてしまい static string UserName = null ; という書き方を試したのですが 「nullリテラルをnull非許容参照型に変換できません」 という警告が出てしまい、警告を出さない書き方が分からず困っている状態です。 どなたか修正方法を教えて頂けないでしょうか? 【ソースコード】 static class Program { static string UserName; static void Name() { Console.WriteLine("ユーザ名を入力してください"); string? enterName = Console.ReadLine(); Console.WriteLine("ユーザ名を入力してください: {0}", enterName); UserName = enterName; } 以下省略

  • C#でプロパティをもつ構造体型の変数を使う

    C#のプログラム struct S { public int A; } class Program { static void Main(string[] args) { S z; z.A = 0; } } には文法エラーはありません。 ところが、構造体の定義を struct S { private int a; public int A { set { a = value; } get { return a; } } } に変えると、Mainメソッドの z.A = 0; の行で 「未割り当てのローカル変数 'z' が使用されました。」 のエラーが出ます。 その上の行を S z = new S(); に変えれば、このエラーはなくなります。 このエラーはどうして出るのでしょうか。 なお、 S[] x = new x[10]; のように、構造体の配列にすると、(配列要素には値が割り当てられてはいないのに、) x[0].A = 1; としてもエラーは出ません。

  • GCCで暗黙の型変換の警告を出したい

    情報が失われてしまうような代入について警告を出したいのですが、 どういったオプションを用いればよいでしょうか? コンパイラはGCCの3.x系か4.x系でお願いします。 以下のようなソースで型変換に関する警告がほしいんです。 --- test.c --- #include <stdio.h> int main(void) {   int a = 66000;   short b;   b = a; // <- 暗黙の型変換   printf("%d\n", b);   return 0; } 実行結果 $ ./test 464 以下のオプションを試しましたが、上記のソースでは 何の警告も出ませんでした。 -W -Wall -Wconversion -Wimplicit ご存知の方いらっしゃいましたら、どうかお助け下さい。

  • C++テンプレートクラスの内部クラスについて

    テンプレートクラスについていろいろ試していたところ以下のようなコードで struct A {     struct AA { };     operator A::AA() { return A::AA(); } // (1) }; template<typename T> struct B {     struct BB { };     template<typename U>     operator B<U>() { return B<U>(); } // (2)     template<typename U>     operator typename B<U>::BB() { return typename B<U>::BB(); } // (3) }; int main() {     static_cast<A::AA>(A()); // (1) ok     static_cast<B<int> >(B<short>()); // (2) ok     static_cast<B<int>::BB>(B<short>()); // (3) compile error     return 0; } (1)と(2)はできて(3)だけがコンパイルを通りませんでした。 試したコンパイラはVC9とg++(3.3.4)とbcc32(5.5.1)で、VC9では以下のようなエラーをはきました。 「error C2440: 'static_cast' : 'B<T>' から 'B<T>::BB' に変換できません。     with [ T=short ] and [ T=int ] コンストラクタはソース型を持てません、またはコンストラクタのオーバーロードの解決があいまいです。」 (1)と(2)ができれば(3)のようなこともできそうな感じがしたのですが、他に書き方があるのでしょうか。 どなたかご存知の方がいらっしゃいましたらご教示お願いします。

  • C#で実行時にメソッドの返り値の型を変化させる

    C# で、実行時にメソッドの返り値の型を変化させることは可能でしょうか? たとえば、 public class MyData { object o; public void setValue( object a ) { o = a; } public object getValue() { return o; } } というクラスがあるとき、 static void Main(string[] args) { MyData a = new MyData(); a.setValue( 3 ); Console.WriteLine( a.getValue().GetType().ToString() ); int i = (int)a.getValue(); } というコードを実行すると、 System.Int32 と表示されます。Main の 4 行目で、(int)のキャストをはずすと、object から int への暗黙の変換はできませんというコンパイルエラーになります。 この(int)のキャストをしなくてもエラーにならないような getValue の関数はできないでしょうか? o は、数値型であるとします。 たとえば、MyData に、 public int getInt() { return (int)o; } とすれば、必ず int を返すようなメソッドはできると思うのですが、これだと、getByte() や、getDouble() などのように、考えられるすべての型を想定してメソッドを作ることになってしまいます。 そうではなく、getValue() で、少なくとも数値型の暗黙の変換はしてくれるようなことにできないでしょうか。 よろしくお願いします。