「C Sharp」の版間の差分

ナビゲーションに移動 検索に移動
23,281 バイト除去 、 1 か月前
クラスをサブページ化したので、こちらメインページからは除去。
(→‎目次: C Sharp/変数)
(クラスをサブページ化したので、こちらメインページからは除去。)
* [[C Sharp/変数]]
* [[C Sharp/クラスとメソッド]]
* C Sharp/条件分岐
* C Sharp/ループや繰り返し
 
== ※編集中 ==
 
C# は現在では国際規格化されており、マイクロソフトの仕様とは独自に国際規格が存在しています。
 
 
=== 変数の宣言 ===
==== 型推論 var ====
変数の宣言の際、intやcharなどの具体的な型を指定しなくても、宣言時の代入で具体的な数値または文字列の代入といっしょにvar とだけ指定すれば、代入されるデータから型を自動的に判断してくれます。なおvarとは「変数」を意味する英語 variable (ヴァリアブル)の略です。
 
:<syntaxhighlight lang="csharp">
using System;
 
public class sample {
public static void Main(string[] args) {
 
var a = 4;
Console.WriteLine(a);
Console.WriteLine( a.GetType() );
var b = "hello";
Console.WriteLine(b);
Console.WriteLine( b.GetType() );
var c = 1.52;
Console.WriteLine(c);
Console.WriteLine( c.GetType() );
var d = "w";
Console.WriteLine(d);
Console.WriteLine( d.GetType() );
 
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
4
System.Int32
hello
System.String
1.52
System.Double
w
System.String
 
</syntaxhighlight>
 
 
C#9 以降、下記のように簡略できます。
:<syntaxhighlight lang="csharp">
var a = 4;
Console.WriteLine(a);
Console.WriteLine( a.GetType() );
var b = "hello";
Console.WriteLine(b);
Console.WriteLine( b.GetType() );
var c = 1.52;
Console.WriteLine(c);
Console.WriteLine( c.GetType() );
var d = "w";
Console.WriteLine(d);
Console.WriteLine( d.GetType() );
</syntaxhighlight>
 
 
どちらにせよ、右辺値のない状態でvarキーワードを使うとエラーになり、コンパイルできません。varキーワードは右辺値から型を推論するキーワードなので、その右辺値そのものが無いと推論できないからです。
 
ほか、あるオブジェクトの型を取得するには、そのオブジェクトから .GetType() メソッドを使います。あるオブジェクトを指定してメソッドを使うには、<code>オブジェクト名.メソッド名()</code>の表記で実行します。
 
似たようなメソッドとして typeof() というのがありますが、これはクラスに対して用いるものと、記法が異なるので、このセクションでのtypeofの説明は省略します。
 
 
var は型を右辺から推論してくれますが、しかし、いちどある変数の型が指定されたら、C#では、その変数の型は変更できません。
 
==== 型を指定した宣言 ====
varを使わずとも、下記のようにC言語と同様の従来の記法で変数宣言することもできます。
 
:<syntaxhighlight lang="csharp">
using System;
 
public class sample {
public static void Main(string[] args) {
 
int a = 17;
Console.WriteLine(a);
Console.WriteLine( a.GetType() );
 
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
17
System.Int32
</syntaxhighlight>
 
また、この例から分かるように int は System.Int32 と同じです。
 
なお、 int とは、「整数」を意味する英語 integer インテジャーの略です。
 
C# では、変数の型は、宣言後は(型を)変更できません。他のプログラミング言語だと、宣言時に数値を代入した変数にあとで文字列を代入できしまうのもあるが、C#ではそういうのは不可能です。
 
C# で宣言されている変数は、原則、どこかのクラスに所属していなければならない。C++のような感覚でもしコード冒頭のどこの class宣言もない部分で変数宣言するとエラーになりコンパイルできない。
 
:<syntaxhighlight lang="csharp">
// エラーになる
using System;
 
var a = 4; // 変数宣言がクラスに包まれていないのでエラーになる。
 
public class sample {
public static void Main(string[] args) {
Console.WriteLine(a);
 
}
}
</syntaxhighlight>
; 実行結果
:エラーになりコンパイル不可
 
 
この仕様は明らかにC#やその手本のJavaが採用した「カプセル化」などの概念に基づいており、本質的な仕様であろう。「カプセル化」の概念とは、プログラムの部品をむきだしで管理することはせず、「カプセル」と言われるグループ単位でモジュール的・パッケージ的に管理することで大規模開発を効率化しようという1990~2001年頃の流行概念である。
 
つまり、C#には、C言語でいうところの「グローバル変数」は無い。開発元のマイクロソフトの公式ドキュメントでも、そう明言されています[https://docs.microsoft.com/ja-jp/dotnet/csharp/fundamentals/object-oriented/ Microsoft Docs 日本語訳『C# のクラス、構造体、レコードの概要』2022/06/10] (2022年6月18日に確認)。
 
これはつまりC#では、すべての変数は、なんらかのクラスに属するメンバです。
 
もしC#でどこからもアクセスしたい変数を定義したい場合は(ただし同じソースコードファイル内)、下記コードのように単に public class でクラス宣言しておいて、必要に応じてクラス内の変数宣言で static 修飾子をつけて宣言すればいいだけである。
 
 
:<syntaxhighlight lang="csharp">
using System;
 
// このクラス testval がどこからでもアクセスできて書き換え可能
public class testval{
public static int a = 3;
public static int b =15;
}
 
public class sample {
public static void Main(string[] args) {
 
Console.WriteLine(testval.a);
 
testval.a = 203;
testval.b = 215;
Console.WriteLine(testval.a);
 
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
3
203
</syntaxhighlight>
 
 
上記のような、どこからでもアクセスできるstatic変数をどう使うかについては、初心者には高度なので、クラスの節で別途に説明する。
 
別ファイルからのアクセスについては、初心者レベルを越えるので、当面の間、説明は省略する。
 
また、クラス側では変数宣言 var は不要です。新しく定義したクラス内で var で型推論をしようとするとエラーになります。
 
下記のように、「ローカル変数でないものをvarで宣言するな」(意訳)とコンパイラに叱られます。
 
<pre>
test.cs(5,19): error CS0825: The contextual keyword `var' may only appear within a local variable declaration
</pre>
 
このように、varには、型推論のほかにも、色々な意味があります。ローカル変数とはメソッド内(C言語でいう「関数」内)で定義されている変数のことです。
 
つまり、C++でいうところの、なんらかの「関数」内でないと(C#でいう「メソッド」内でないと)、varは使えません。
 
 
よく分からなければ、どこからでも出来るグローバル変数的なものをC#で作りたい場合、初心者のうちは、Main 関数内で変数宣言すれば、基本的に同じコードファイル中のどこからでもアクセスできるはずです。
 
グローバル変数的な管理用の public class などを別途に作るのは、慣れてきてからで十分です。
 
C++などと比べて一見すると面倒そうですし実際に初心者にとっての障壁のひとつですが、C#ではグローバル変数的にどこからでもアクセスできる変数を必要に応じてクラスでグループ化できるという、C++や標準Cにはない利点もあります。
 
そもそもクラスやその元ネタの構造体は、いくつもある要素のグループ化のためのものです。
 
 
==== 定数の宣言 ====
書き換え不能な変数を「定数」と言います。
 
値が変化しないのに「変数」というのも妙ですが、歴史的にそう言うのと、他によい言い回しがないので、そういうものだと割り切ってください。
 
C#で変数を宣言するには const キーワードを使います。(C++ や 標準C と同じです。)
 
var と const は併用できません。
 
<code>const int a</code> のように型指定(int の部分)といっしょに const を宣言することで使えます。
 
:<syntaxhighlight lang="csharp">
using System;
 
public class sample {
public static void Main(string[] args) {
 
const int a = 4;
Console.WriteLine(a);
 
// a = 7; // const変数を書き換えようとしているので、コメントアウトしないとエラー
 
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
4
</syntaxhighlight>
 
 
もし、上記コードから<code>const</code>のキーワード部分を消せば、コメントアウトした<code> a = 7; </code> をコメントアウトしなくても実行できるようになります。読者はそれぞれ試してください(ほぼ同じ内容の繰り返しになるので、説明は省略)。
 
 
 
=== 書式指定 ===
実行結果の2行目と3行目を見比べれば分かるように、2行目の結果でwith書き換えをした派生変数 person02 を作成しても、もとのrecord型変数 person01 はそのままです。
 
== メソッドとクラス ==
 
C# の「メソッド」と「クラス」の概念はお互いに関連しあっており、やや難しい。メソッドを読んでて分からなければ、とりあえずクラスも読んでみるのが良い。
 
=== メソッド ===
C言語でいう「関数」に似た機能として、c#では「メソッド」がある。
 
関数との違いとして、メソッドは必ずどこかのクラスまたは構造体に所属していなければならない。開発元のマイクロソフトの公式ドキュメントでも、そう明言されています[https://docs.microsoft.com/ja-jp/dotnet/csharp/fundamentals/object-oriented/ Microsoft Docs 日本語訳『C# のクラス、構造体、レコードの概要』2022/06/10] (2022年6月18日に確認)。
 
つまり、必ずどこかのクラスまたは構造体のブロック中にてメソッドは宣言されることになる。どこのクラスにも属してない むきだしのメソッドを宣言しても、それがコード中に存在しているだけでコンパイルできずにエラーになる。
 
:うごくコード例<syntaxhighlight lang="csharp">
using System;
 
// ユーザー定義側のメソッドには public はなくてもいい
class testclass{
static public void testfunc (){
var a = 55;
Console.WriteLine(a);
}
}
 
public class sample {
public static void Main(string[] args) {
 
testclass.testfunc();
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
55
</syntaxhighlight>
 
 
同じクラスの中にある関数を呼び出す場合なら、呼出時のクラス指定を省略できる。
 
:<syntaxhighlight lang="csharp">
using System;
 
public class sample {
public static void Main(string[] args) {
 
testfunc();
}
static public void testfunc (){
var a = 14;
Console.WriteLine(a);
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
14
</syntaxhighlight>
 
 
なお、変数宣言で用いる var は、メソッド内でのローカル変数の宣言です。
 
ただし、Mainメソッドのブロック内のvarだけ、Mainメソッドよりも上位のメソッドは無いので結果的にMainメソッド内のvar宣言された変数があたかもグローバル変数のような働きをしますが、あくまで結果論です。
 
 
 
さて、C#のカプセル化などの理念により、すべての変数は、なんらかのクラスに所属していなければなりません。
 
変数宣言で static 修飾子をつけると、どこからでもアクセスできるし、どこでアクセスして読み書きしても結果は共有されます。このため、static修飾をつけることで、標準C や C++ でいうグローバル変数のように使えます。
 
 
下記コードでは、Mainメソッド以外のユーザ定義メソッドから書き換えをできるかのテストをしています。
 
:うごくコード例<syntaxhighlight lang="csharp">
using System;
 
// 変数管理用
public class testval{
public static int a = 3;
public static int b =15; // 使わないけど比較用
}
 
// ユーザ定義メソッド
class testclass{
static public void testfunc (){
// 書き換えテスト
testval.a = 403;
testval.b = 415;
Console.WriteLine("ユーザー定義メソッドにて書き換え実行");
}
}
 
// Mainメソッド
public class sample {
public static void Main(string[] args) {
 
Console.WriteLine("aは");
Console.WriteLine(testval.a);
//test inst = new test();
Console.WriteLine("Main側での書き換えテスト");
testval.a = 203;
//testval.b = 215;
Console.WriteLine(testval.a);
 
Console.WriteLine("これからユーザー定義メソッドでさらに書き換えを試みる");
testclass.testfunc();
Console.WriteLine("今、Mainに戻ったあとです");
 
Console.WriteLine("aは");
Console.WriteLine(testval.a);
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
aは
3
Main関数側での書き換えテスト
203
これからユーザー定義関数でさらに書き換えを試みる
ユーザー定義関数にて書き換え実行
今、Main関数に戻ったあとです
aは
403
</syntaxhighlight>
 
このように、staticで宣言された変数は、書き換えしたメソッドとは他のメソッドに移っても、書き換えの結果が保存されています。
 
「でもMainメソッドは、ユーザ定義メソッドの呼出元じゃないか? 呼出元以外ではどうなるんだ?」と疑問に思うなら、どうぞ試してください。結果は、Main以外の場所で結果確認をしても、上記コードと同様に書き換え結果は保存されます。
 
 
:うごくコード例<syntaxhighlight lang="csharp">
using System;
 
// 変数管理用
public class testval{
public static int a = 3;
public static int b =15; // 使わないけど比較用
}
 
// ユーザ定義メソッド
class testclass{
static public void testfunc (){
// 書き換えテスト
testval.a = 403;
testval.b = 415;
Console.WriteLine("ユーザー定義メソッドにて書き換え実行");
}
}
 
// 結果確認用メソッド
class testcheck{
static public void testfunc2 (){
Console.WriteLine("aは");
Console.WriteLine(testval.a);
}
}
 
// Mainメソッド
public class sample {
public static void Main(string[] args) {
 
Console.WriteLine("aは");
Console.WriteLine(testval.a);
//test inst = new test();
Console.WriteLine("Main側での書き換えテスト");
testval.a = 203;
//testval.b = 215;
Console.WriteLine(testval.a);
 
Console.WriteLine("これからユーザー定義メソッドでさらに書き換えを試みる");
testclass.testfunc();
Console.WriteLine("今、Mainに戻ったあとです");
 
Console.WriteLine("結果チェック用メソッドに移動します");
testcheck.testfunc2();
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
aは
3
Main側での書き換えテスト
203
これからユーザー定義メソッドでさらに書き換えを試みる
ユーザー定義メソッドにて書き換え実行
今、Mainに戻ったあとです
結果チェック用メソッドに移動します
aは
403
</syntaxhighlight>
 
このように、とにかくstatic宣言された変数は、標準CやC++でいうグローバル変数的に振る舞います。
 
static 変数にアクセスする場合、インスタンスの作成は不要です。
 
 
また、相手先のメソッドの位置さえ分かるように呼び出せば、そのメソッドがpublicならアクセスできます。呼び出し元がどこのクラスにいるかは、呼び出し方法の指定には基本、関係ありません。
 
後述のクラスでも同様、相手先の変数がどのクラスにいるかさえ分かるように指定すれば、事前に適切な処理がされていれば、その変数にアクセスできます。
 
 
上記の説明では不要だってので説明省略しましたが、C#のメソッドは戻り値(返却値、返り値)をひとつ持てます。C++などと同様です。
戻り値の型 メソッド名 (引数1の型 引数名1, 引数2の型 引数名2 ) {
のような書式です。void は、「戻り値は無し」を意味します。
 
引数が特に無い場合、下記のように、引数名とその型を省略できます。
void testfunc (){
 
=== クラス ===
C++でいうクラスは、データの集合をあらわすものの事である標準C言語とC++でいう「構造体」も、若干の違いはあるがクラスと似たようなものである。
 
だがC#は理念として、あらゆるものをクラスまたは構造体で管理するという方針があるので、C++的なクラスの性質だけでなく、C#特有の独特の性質がある。
 
==== 基本 ====
クラスの基本的な使いかたは下記のとおり。
 
コード例<syntaxhighlight lang="csharp">
using System;
 
class testclass {
public string name;
public int price;
}
 
public class sample {
public static void Main(string[] args) {
 
testclass a = new testclass() ;
 
a.name = "牛乳";
a.price = 140;
Console.WriteLine(a.name);
Console.WriteLine(a.price);
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
牛乳
140
</syntaxhighlight>
 
上記コードでいう <code>string name;</code> や <code>int price;</code> などをメンバという。C言語の構造体やC++の構造体/クラスでも同様の働きをするものを「メンバ」と言う。C#の用語はC++を踏襲したものである。
 
メンバは public にアクセス修飾子を指定しないかぎり、基本的には直接はアクセスできない。
 
 
クラス側の変数宣言において、static 宣言されていない変数は、インスタンスを作成しないかぎり、使うことは出来ません。
 
インスタンスの生成には、new キーワードを使います。上記コードでいう、
<syntaxhighlight lang="csharp">
testclass a = new testclass() ;
</syntaxhighlight>
がインスタンスの生成です。書式は、
<syntaxhighlight lang="csharp">
クラス名 変数名 = new クラス名() ;
</syntaxhighlight>
です。
 
左辺の「変数名」をクラス変数とかインスタンス変数とか呼びたくなりますが、しかし既に「クラス変数」「インスタンス変数」はプログラミング界隈では別の意味で使われている用語ですので、ここでは単に「変数」「変数名」と呼ぶことにしましょう。
 
また、別々のインスタンスに属する変数は、それぞれ別の変数です。単に、「クラス」とは型の情報や初期値などを提供するだけです。つまりクラスは、変数の集まりをつくるときのメモ帳です。
 
個々の変数の実体は、原則的に、(クラス側ではなく)インスタンス側でされています。
 
試しに、複数のインスタンスを作って確認してみましょう。
 
コード例<syntaxhighlight lang="csharp">
using System;
 
class testclass {
public string name;
public int price;
}
 
public class sample {
public static void Main(string[] args) {
 
testclass a = new testclass() ;
 
a.name = "牛乳";
a.price = 140;
Console.WriteLine(a.name);
Console.WriteLine(a.price);
Console.WriteLine();
// 別インスタンスを作成
testclass b = new testclass() ;
 
b.name = "みかんジュース";
b.price = 120;
Console.WriteLine(b.name);
Console.WriteLine(b.price);
Console.WriteLine();
// 牛乳の情報が残ってるかの確認
Console.WriteLine(a.name);
Console.WriteLine(a.price);
Console.WriteLine();
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
牛乳
140
 
みかんジュース
120
 
牛乳
140
 
</syntaxhighlight>
 
このように、最低でも宣言したインスタンスのぶんだけ、変数は新規に確保されます。また、別々のインスタンスにもとづく変数は、それぞれ別個の変数です。なので、上記コードでは「みかんジュース」を宣言しようが「牛乳」はそのまま問題なく残りつづけます。
 
==== コンストラクタ ====
下記コードのように、構造体またはクラス中に、構造体名あるいはクラス名と同じメソッド名をもつメソッドを書くと、その構造体/クラスを呼び出したときの処理を指定できる。
 
コード例<syntaxhighlight lang="csharp">
using System;
 
struct teststr {
public string name;
public int price;
public teststr(string a, int b){
name = a;
price = b;
}
}
 
public class sample {
public static void Main(string[] args) {
 
teststr milk = new teststr("牛乳", 150);
Console.WriteLine(milk.name);
Console.WriteLine(milk.price);
Console.WriteLine();
teststr cmilk = new teststr("コーヒー牛乳", 180);
Console.WriteLine(cmilk.name);
Console.WriteLine(cmilk.price);
Console.WriteLine();
Console.WriteLine(milk.name);
Console.WriteLine(milk.price);
Console.WriteLine();
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
牛乳
150
 
コーヒー牛乳
180
 
牛乳
150
 
</syntaxhighlight>
 
== クラスと構造体の違い ==
 
論より証拠、実際に構造体とクラスのコードをそれぞれ実行して結果を比べてみましょう。
 
まず、<code>milk.price = 150;</code>のようにメンバに直接に代入する場合は、クラスでも構造体でも結果は下記のように同じです。
 
コード例<syntaxhighlight lang="csharp">
using System;
 
struct teststr {
public string name;
public int price;
}
 
public class sample {
public static void Main(string[] args) {
 
teststr milk = new teststr();
milk.name = "牛乳";
milk.price = 150;
 
teststr cmilk = new teststr();
cmilk.name = "コーヒー牛乳";
cmilk.price = 180;
 
Console.WriteLine(cmilk.name);
Console.WriteLine(cmilk.price);
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
コーヒー牛乳
180
</syntaxhighlight>
 
 
 
コード例<syntaxhighlight lang="csharp">
using System;
 
class testclass {
public string name;
public int price;
}
 
public class sample {
public static void Main(string[] args) {
 
testclass milk = new testclass();
milk.name = "牛乳";
milk.price = 150;
 
testclass cmilk = new testclass();
cmilk.name = "コーヒー牛乳";
cmilk.price = 180;
 
Console.WriteLine(cmilk.name);
Console.WriteLine(cmilk.price);
}
}
</syntaxhighlight>
; 実行結果 :<syntaxhighlight lang="text">
コーヒー牛乳
180
</syntaxhighlight>
 
では違いはというと、・・・※調査中
 
{{NDC|007.64}}
23,090

回編集

案内メニュー