C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

int構造体やstringクラス型変数に値を格納できる理由

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■83115 / inTopicNo.1)  int構造体やstringクラス型変数に値を格納できる理由
  
□投稿者/ rotto (3回)-(2017/03/07(Tue) 08:45:33)

分類:[.NET 全般] 

タイトルの通りです。intについて質問させてください
intは構造体の型の変数にそのまま値が格納できます。

例えばコード上では
int i = 144;

という風に値が格納できます。

しかし、通常の構造体型の変数には
値を格納する事はできません。

例えば、下記のように自作の構造体を作成したとします。

public struct ItumonoKozoutai
{
public int I{get;set;}
public int k;
}

この場合、構造体に直接値を格納するわけではなく
フィールドに値を格納するか、プロパティを介して
フィールドに値を格納します。

ItumonoKozoutai itumono;
itumono.k = 100;
itumono.I = 130;

という感じです。

しかし、intの場合は上記方法ではなく
int int_i;
int_i = 100;
という風に値を格納できます。

なぜ、intの場合は
構造体型の変数に直接値を格納できるのでしょうか?

構造体型の変数に直接値を格納できる構造体は
自分でも作成できるのでしょうか?

そして、stringはクラスなわけですが

string str_s;
str_s = "かきくけこ";

で値を格納できます。
しかもstringの場合は上記方法に加えて

string str_s2;
str_s2 = new string(new char[] {'か','き','く','け','こ'});

でも値を格納できます。
stringはイミュータブルオブジェクトなので
常に新規作成されるイメージ
値型と同じような感じになる、というのは聞いているのですが

このように
str_s = "かきくけこ"; で値を入れた場合
強制的にnewをされるクラスというのは

自分で自作出来るのでしょうか?

上記疑問点を教えてほしいのです。

疑問点のまとめ

1.int a = 130; や string s = "かきくけこ";
で構造体の型やクラスの型に直接値を格納できるのはなぜか?

2.string str_s = "かきくけこ"が
string str_s = new string(new char[] {'か','き','く','け','こ'});
と同様のコードになる理由

3・2のように同様のコードで値を格納出来るクラスは自作できるのか?
自作できるのであれば、どのようにして作るのか?

上記が疑問点のまとめです。
ご存知の方がいらっしゃいましたら、教えてください
よろしくお願いいたします。


引用返信 編集キー/
■83117 / inTopicNo.2)  Re[1]: int構造体やstringクラス型変数に値を格納できる理由
□投稿者/ Hongliang (507回)-(2017/03/07(Tue) 09:26:04)
> 1.int a = 130; や string s = "かきくけこ";
> で構造体の型やクラスの型に直接値を格納できるのはなぜか?

130はint型の値なので、当然代入できます。
同様に"かきくけこ"はstring型の値なので、当然代入できます。
130がint型として、"かきくけこ"がstring型として扱われるのは、
コンパイラがむき出しの数字列や""で区切られた部分をそのように扱うからとしか言い様がないですね。

> 2.string str_s = "かきくけこ"が
> string str_s = new string(new char[] {'か','き','く','け','こ'});
> と同様のコードになる理由

後者は、単にstringにそういうコンストラクタが用意されているからです。
なお、リテラル文字列はインターンプールというところに格納され、
同じ文字列であれば同じインスタンスを共有するので、
厳密にはa = "..."とa = new string(...)は異なります。
Object.ReferenceEquals("a", "a") // true
Object.ReferenceEquals("a", new string(new[]{'a'})) // false
Object.ReferenceEquals(new string(new[]{'a'}), new string(new[]{'a'})) // false

> 3・2のように同様のコードで値を格納出来るクラスは自作できるのか?
> 自作できるのであれば、どのようにして作るのか?

暗黙の型変換を定義すれば、一つの数値などからインスタンスに代入することはできます。
struct Hoge {
    private int m_Value;
    public int Value { get { return this.m_Value; } }
    public Hoge(int value) { this.m_Value = value; }
    public static implicit operator Hoge(int value) {
        return new Hoge(value);
    }
}
Hoge a = 4;

引用返信 編集キー/
■83118 / inTopicNo.3)  Re[1]: int構造体やstringクラス型変数に値を格納できる理由
□投稿者/ 774RR (478回)-(2017/03/07(Tue) 09:26:51)
A1-1. C# の int は「構造体」ではなくて単なる値型。だから i=144; はできて当たり前。
class 自体は参照型だけど、クラスのメンバは値型にできるので以下同文。

A1-2. ここの s は参照型だからどこかにある実体を指しているだけの話。
A2. も A1-2 と同様。

A3. reference source から System.String のソース見てみるとか
https://referencesource.microsoft.com/
単に各演算が、演算結果を new String して返すだけの話だと・・・


引用返信 編集キー/
■83120 / inTopicNo.4)  Re[1]: int構造体やstringクラス型変数に値を格納できる理由
□投稿者/ 魔界の仮面弁士 (1166回)-(2017/03/07(Tue) 09:33:29)
No83115 (rotto さん) に返信
> intは構造体の型の変数にそのまま値が格納できます。

これは .NET 側の仕様と言うよりも、整数型の数値リテラルとして
言語仕様レベルで定義されているためだと思います。

整数値の代入は、IL レベルで専用命令が用意されているので、
整数リテラルが用意されていた方が都合が良かったのでしょう。


たとえば deciemal 構造体の場合などは、
  decimal a = 1.234M;
  decimal b = 1.23400m;

  Console.WriteLine(a); // 1.234
  Console.WriteLine(b); // 1.23400
  Console.WriteLine(a == b); // True
  Console.WriteLine(a.ToString() == b.ToString()); // False
のように、M/m サフィックスによるリテラル表記が用意されてはいます。

といっても、Visual Studio のデザイナコードにおいては、コードジェネレーターが
  a = new decimal(new int[] {1234, 0, 0, 196608});
のようにコンストラクタを用いた記述を生成するようになっていますけれどね。


あるいは DateTiem 構造体を例に挙げてみると:
Visual Basic には「日付型リテラル」が存在しており、
 Dim dt1 As DateTime = #3/7/2017 8:45:00 AM#
のような記述ができますが、C# にはそのようなリテラルが存在しないため
DateTime 構造体のコンストラクタや Parse/ParseExact メソッドなどを用いて
 DateTime dt2 = new DateTime(2017, 3, 7, 8, 45, 0);
 DateTime dt3 = DateTime.Parse("2017-03-07 08:45:00");
と書かねばなりません。




> 例えば、下記のように自作の構造体を作成したとします。

オブジェクト初期化子を用いて、
  ItumonoKozoutai kouzoutai = new ItumonoKozoutai() { I = 111, k = 222 };
のように指定することはできます(C# 3.0/VS2008 以上)。

それ以前のバージョンだと、ItumonoKozoutai 型を返す静的メソッドか、
引数付きコンストラクタを、ItumonoKozoutai 構造体に用意することで、
  ItumonoKozoutai kouzoutai1 = new ItumonoKozoutai(333, 444);
  ItumonoKozoutai kouzoutai2 = ItumonoKozoutai.Create(555, 666);
などの記述が可能になります。


> フィールドに値を格納するか、プロパティを介して
> フィールドに値を格納します。
たとえば、ItumonoKozoutai 構造体にて

 public static implicit operator ItumonoKozoutai(ulong qword)
 {
   return new ItumonoKozoutai() { I = (int)(qword >> 32), k = (int)(qword & uint.MaxValue) };
 }

のような型変換演算子をオーバーロードさせておけば、
 // 下記は、X = 0xFEDCBA98, k = 0x76543210 の代入として扱われる
 ItumonoKozoutai kouzoutai = 0xfedcba9876543210ul;
のような書き方ができます。String 型からの変換を受け付けるようにすれば、
 ItumonoKozoutai kouzoutai = "1234,5678";
とも書けるようになるでしょう。


> str_s = "かきくけこ"; で値を入れた場合
> 強制的にnewをされるクラスというのは

オブジェクト初期化子、静的メソッド、引数付きコンストラクタ、あるいは
explicit / implicit などといった演算子のオーバーロードで対応することはできます。

ただ、リテラル表記そのものについては言語仕様レベルの話になるので、
自分では自由に追加できません。なお、C# 6.0 (VS2015) においては、
 System.IFormattable formatable = $"({x}, {y})";
のようなリテラルが追加されていますね。
引用返信 編集キー/
■83137 / inTopicNo.5)  Re[1]: int構造体やstringクラス型変数に値を格納できる理由
□投稿者/ shu (970回)-(2017/03/07(Tue) 22:19:21)
No83115 (rotto さん) に返信


> なぜ、intの場合は
> 構造体型の変数に直接値を格納できるのでしょうか?
出来る仕様にしておかないといろいろ面倒だしそんな仕様に
することする出来ないかもしれないから

例えば提示された
> int i = 144;
このように書けないとすると
int i;
i.value = 144;
のようになるかもしれませんが
このvalueはint型なので
i.value.value = 144;
となります。
このように考えていくと疑問を解決するような
書き方は出来ないことがわかるかと思います。


なので単純な型は簡単な表記で代入が出来る必要があります。
引用返信 編集キー/
■83193 / inTopicNo.6)  Re[2]: int構造体やstringクラス型変数に値を格納できる理由
□投稿者/ rotto (4回)-(2017/03/11(Sat) 08:58:51)
みなさん、回答ありがとうございます。
おかげさまで、理解する事ができました
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ