M.Hiroi's Home Page

C# Programming

お気楽C#プログラミング超入門 (前編)

[ Home | C# ]

C# の基礎知識

●基本的なデータ型

$ dotnet script
> int[] a = new int[10]; 
> a[0]
0
> a[9] = 1;
> a[9]
1
> int[,] b = {{1,2,3},{4,5,6},{7,8,9}};
> b[0,0]
1
> b[2,2]
9
> b[2,2] = 10;
> b[2,2]
10
> var c = new int[3, 4];
> c.Length
12
> c.GetLength(0)
3
> c.GetLength(1)
4

●基本的な演算子

●基本的な制御構造

●関数

リスト : 階乗とフィボナッチ関数 (sample01/Program.cs)

using System;

class Test {
  // 再帰
  static long Fact(long n) {
    return n == 0 ? 1 : n * Fact(n - 1);
  }

  // 繰り返し
  static long Facti(long n) {
    long a = 1;
    for (long i = 2; i <= n; i++) a *= i;
    return a;
  }

  // 再帰
  static int Fibo(int n) {
    if (n < 2) return n;
    return Fibo(n - 2) + Fibo(n - 1);
  }

  // 繰り返し
  static int Fiboi(int n) {
    int a = 0, b = 1;
    while (n-- > 0) {
      int c = a + b;
      a = b;
      b = c;
    }
    return a;
  }

  static void Main() {
    Console.WriteLine("{0}! = {1}", 10, Fact(10));
    Console.WriteLine("{0}! = {1}", 15, Fact(15));
    Console.WriteLine("{0}! = {1}", 20, Fact(20));
    Console.WriteLine("{0}! = {1}", 10, Facti(10));
    Console.WriteLine("{0}! = {1}", 15, Facti(15));
    Console.WriteLine("{0}! = {1}", 20, Facti(20));
    Console.WriteLine("Fibo({0}) = {1}", 10, Fibo(10));
    Console.WriteLine("Fibo({0}) = {1}", 15, Fibo(15));
    Console.WriteLine("Fibo({0}) = {1}", 20, Fibo(20));
    Console.WriteLine("Fiboi({0}) = {1}", 10, Fiboi(10));
    Console.WriteLine("Fiboi({0}) = {1}", 15, Fiboi(15));
    Console.WriteLine("Fiboi({0}) = {1}", 20, Fiboi(20));
  }
}
$ dotnet run --project sample01
10! = 3628800
15! = 1307674368000
20! = 2432902008176640000
10! = 3628800
15! = 1307674368000
20! = 2432902008176640000
Fibo(10) = 55
Fibo(15) = 610
Fibo(20) = 6765
Fiboi(10) = 55
Fiboi(15) = 610
Fiboi(20) = 6765

●変数

●クラス

リスト : 簡単な例題 (sample02/Program.cs)

using System;

class Point {
  double x = 0.0, y = 0.0;

  // コンストラクタ
  public Point() { }
  public Point(double x, double y) {
    this.x = x;
    this.y = y;
  }

  // メソッド
  public double Distance(Point p) {
    double dx = x - p.x;
    double dy = y - p.y;
    return Math.Sqrt(dx * dx + dy * dy);
  }
}

class Point3D {
  double x = 0.0, y = 0.0, z = 0.0;

  // コンストラクタ
  public Point3D() { }
  public Point3D(double x, double y, double z) {
    this.x = x;
    this.y = y;
    this.z = z;
  }

  // メソッド
  public double Distance(Point3D p) {
    double dx = x - p.x;
    double dy = y - p.y;
    double dz = z - p.z;
    return Math.Sqrt(dx * dx + dy * dy + dz * dz);
  }
}

class Test {
  static void Main() {
    var p1 = new Point();
    var p2 = new Point(1.0, 1.0);
    Console.WriteLine("{0}", p1.Distance(p2));
    var p3 = new Point3D();
    var p4 = new Point3D(1.0, 1.0, 1.0);
    Console.WriteLine("{0}", p3.Distance(p4));
  }
}
$ dotnet run --project sample02
1.4142135623730951
1.7320508075688772

●継承

リスト : 継承の簡単なサンプル (sample03/Program.cs)

using System;

class Foo {
  int x = 0, y = 0;

  public Foo() {}
  public Foo(int a, int b) {
    x = a;
    y = b;
  }

  // アクセスメソッド
  public int GetX() { return x; }
  public int GetY() { return y; }
  public void SetX(int a) { x = a; }
  public void SetY(int b) { y = b; }

  // 合計値を求める
  public int Sum() {
    return x + y;
  }
}

class Bar : Foo {
  int z = 0;

  public Bar() { }
  public Bar(int a, int b, int c) : base(a, b) {
    z = c;
  }

  // アクセスメソッド
  public int GetZ() { return z; }
  public void SetZ(int c) { z = c; }

  // 合計値を求める
  public new int Sum() {
    return z + base.Sum();
  }
}

class Test {
  static void Main() {
    var a = new Foo(1, 2);
    var b = new Bar(10, 20, 30);
    Console.WriteLine("{0}", a.Sum());  // 3 と表示
    Console.WriteLine("{0}", b.Sum());  // 60 と表示
  }
}
$ dotnet run --project sample03
3
60

●仮想関数とポリモーフィズム

リスト : 仮想関数の簡単な例題 (sample04/Program.cs)

using System;

class Foo {
  int x = 0, y = 0;

  public Foo() {}
  public Foo(int a, int b) {
    x = a;
    y = b;
  }

  // アクセスメソッド
  public int GetX() { return x; }
  public int GetY() { return y; }
  public void SetX(int a) { x = a; }
  public void SetY(int b) { y = b; }

  // 合計値を求める
  public virtual int Sum() {
    return x + y;
  }
}

class Bar : Foo {
  int z = 0;

  public Bar() { }
  public Bar(int a, int b, int c) : base(a, b) {
    z = c;
  }

  // アクセスメソッド
  public int GetZ() { return z; }
  public void SetZ(int c) { z = c; }

  // 合計値を求める
  public override int Sum() {
    return z + base.Sum();
  }
}

class Test {
  static void Main() {
    Foo a = new Foo(1, 2);
    Foo b = new Bar(10, 20, 30);        // アップキャスト
    Console.WriteLine("{0}", a.Sum());  // 3 と表示
    Console.WriteLine("{0}", b.Sum());  // 60 と表示
  }
}
$ dotnet run --project sample04
3
60

●抽象クラスと抽象メソッド

リスト : 抽象クラスと抽象メソッドの簡単な例題 (sample05/Program.cs)

using System;

abstract class Figure {
  public abstract string KindOf();
  public abstract double Area();
  public void Print(){
    Console.WriteLine("{0}: area = {1}", KindOf(), Area());
  }
}

// 三角形
class Triangle : Figure {
  double altitude, base_line;
  public Triangle(double a, double b){
    altitude = a;
    base_line = b;
  }
  public override string KindOf(){
    return "Triangle";
  }
  public override double Area(){
    return altitude * base_line / 2.0;
  }
}

// 四角形
class Rectangle : Figure {
  double width, height;
  public Rectangle(double w, double h){
    width = w;
    height = h;
  }
  public override string KindOf(){
    return "Rectangle";
  }
  public override double Area(){
    return width * height;
  }
}

// 円
class Circle : Figure {
  double radius;
  public Circle(double r){
    radius = r;
  }
  public override string KindOf(){
    return "Circle";
  }
  public override double Area(){
    return radius * radius * Math.PI;
  }
}

class Test {
  static void Main() {
    Triangle a = new Triangle(2.0, 2.0);
    Rectangle b = new Rectangle(2.0, 2.0);
    Circle c = new Circle(2.0);
    a.Print();
    b.Print();
    c.Print();
    Figure[] figTable = {
      new Triangle(3.0, 3.0),
      new Rectangle(3.0, 3.0),
      new Circle(3.0),
    };
    foreach(Figure f in figTable) {
      f.Print();
    }
  }
}
$ dotnet run --project sample05
Triangle: area = 2
Rectangle: area = 4
Circle: area = 12.566370614359172
Triangle: area = 4.5
Rectangle: area = 9
Circle: area = 28.274333882308138

●インターフェース

リスト : インターフェースの簡単な使用例 (sample06/Program.cs)

using System;

// インターフェースの定義
interface Figure {
  string KindOf();
  double Area();
  void Print();
}

// 三角形
class Triangle : Figure {
  double altitude, base_line;
  public Triangle(double a, double b){
    altitude = a;
    base_line = b;
  }
  public string KindOf(){
    return "Triangle";
  }
  public double Area(){
    return altitude * base_line / 2.0;
  }
  public void Print(){
    Console.WriteLine("{0}: area = {1}", KindOf(), Area());
  }
}

// 四角形
class Rectangle : Figure {
  double width, height;
  public Rectangle(double w, double h){
    width = w;
    height = h;
  }
  public string KindOf(){
    return "Rectangle";
  }
  public double Area(){
    return width * height;
  }
  public void Print(){
    Console.WriteLine("{0}: area = {1}", KindOf(), Area());
  }
}

// 円
class Circle : Figure {
  double radius;
  public Circle(double r){
    radius = r;
  }
  public string KindOf(){
    return "Circle";
  }
  public double Area(){
    return radius * radius * Math.PI;
  }
  public void Print(){
    Console.WriteLine("{0}: area = {1}", KindOf(), Area());
  }
}

class Test {
  static void Main() {
    Triangle a = new Triangle(2.0, 2.0);
    Rectangle b = new Rectangle(2.0, 2.0);
    Circle c = new Circle(2.0);
    a.Print();
    b.Print();
    c.Print();
    Figure[] figTable = {
      new Triangle(3.0, 3.0),
      new Rectangle(3.0, 3.0),
      new Circle(3.0),
    };
    foreach(Figure f in figTable) {
      f.Print();
    }
  }
}
$ dotnet run --project sample06
Triangle: area = 2
Rectangle: area = 4
Circle: area = 12.566370614359172
Triangle: area = 4.5
Rectangle: area = 9
Circle: area = 28.274333882308138

●プロパティ

リスト : プロパティの簡単な例題 (sample07/Program.cs)

using System;

class Foo {
  public int X { set; get; }
  public int Y { set; get; }

  // 合計値を求める
  public int Sum {
    get { return X + Y; }
  }
}

// getter だけ自動生成する
class Bar {
  public Bar(int a, int b) {
    X = a;
    Y = b;
  }

  public int X { get; }
  public int Y { get; }

  // 合計値を求める
  public int Sum {
    get { return X + Y; }
  }
}

class Test {
  static void Main() {
    var a = new Foo();
    a.X = 10;
    a.Y = 20;
    Console.WriteLine("{0}", a.Sum);  // 30

    var b = new Bar(10, 20);
    Console.WriteLine("{0}", b.Sum);  // 30
  }
}
$ dotnet run --project sample07
30
30

●ジェネリック

リスト : ジェネリックの簡単な使用例 (sample08/Program.cs)

using System;

class Foo<T> {
  // T だけだとワーニングになるので T? を使う
  // T? は null 許容型 を参照
  T? x;
  public Foo() { x = default(T); }
  public Foo(T n) { x = n; }
  public T? Get() { return x; }
}

class Bar<T> where T : new() {
  T y;
  public Bar() { y = new T(); }
  public Bar(T n) { y = n; }
  public T Get() { return y; }
}

class Baz {
  int z;
  public Baz() { z = 123; }
  public Baz(int n) { z = n; }
  public int Get() { return z; }
}

class Test {
  // 型変数の場合、比較演算子は使えないので、
  // インターフェース IComparable を使う
  static int IndexOf<T>(T[] buff, T x) where T : IComparable {
    for (int i = 0; i < buff.Length; i++) {
      if (x.CompareTo(buff[i]) == 0) return i;
    }
    return -1;
  }

  static void Main() {
    var a = new Foo<int>();
    var b = new Foo<double>(1.2345);
    var c = new Bar<Baz>();
    Console.WriteLine("{0}", a.Get());         // 0
    Console.WriteLine("{0}", b.Get());         // 1.2345
    Console.WriteLine("{0}", c.Get().Get());   // 123

    int[] d = {1,2,3,4,5,6,7,8};
    double[] e = {1.1, 2.2, 3.3, 4.4, 5.5};
    Console.WriteLine("{0}", IndexOf(d, 5));   // 4
    Console.WriteLine("{0}", IndexOf(d, 9));   // -1
    Console.WriteLine("{0}", IndexOf(e, 4.4)); // 3
    Console.WriteLine("{0}", IndexOf(e, 5.0)); // -1
  }
}
$ dotnet run --project sample08
0
1.2345
123
4
-1
3
-1

●構造体

リスト : 構造体とジェネリックの簡単な使用例 (sample09/Program.cs)

using System;

struct Point {
  double x, y;
  public Point(double a, double b) {
    x = a;
    y = b;
  }
  public double Distance(Point p) {
    double dx = x - p.x;
    double dy = y - p.y;
    return Math.Sqrt(dx * dx + dy * dy);
  }
}

struct Pair<T, U> {
  T p;
  U q;
  public Pair(T a, U b) {
    p = a;
    q = b;
  }
  public T Fst() { return p; }
  public U Snd() { return q; }
}

class Test {
  static void Main() {
    Point p1 = new Point();
    Point p2 = new Point(1.0, 1.0);
    Console.WriteLine("{0}", p1.Distance(p2));  // 1.4142135623731

    var a = new Pair<string, int>("foo", 10);
    var b = new Pair<string, double>("bar", 1.2345);
    Console.WriteLine("{0}, {1}", a.Fst(), a.Snd());    // foo, 10
    Console.WriteLine("{0}, {1}", b.Fst(), b.Snd());    // bar, 1.2345
  }
}
$ dotnet run --project sample09
1.4142135623730951
foo, 10
bar, 1.2345

●デリゲートとラムダ式

リスト : デリゲートの簡単な使用例 (sample10/Program.cs)

using System;

class Test {
  // int を受け取って int を返すメソッドの型 IntFunc を定義
  delegate int IntFunc(int x);

  // マッピング (intFunc 型のメソッドを受け取る高階関数)
  static int[] Map(IntFunc func, int[] xs) {
    int[] ys = new int[xs.Length];
    for (int i = 0; i < xs.Length; i++)
      ys[i] = func(xs[i]);
    return ys;
  }

  // 引数を二乗するメソッド
  static int Square(int x) { return x * x; }
  
  static void Main() {
    int[] a = {1, 2, 3, 4, 5};
    foreach(int x in Map(Square, a))
      Console.Write("{0} ", x);        // 1 4 9 16 25 
    Console.WriteLine("");
  }
}
$ dotnet run --project sample10
1 4 9 16 25
リスト : ラムダ式の簡単な使用例 (sample11/Program.cs)

using System;

class Test {
  // 配列のマッピング
  static T[] Map<T>(Func<T, T> func, T[] xs) {
    T[] ys = new T[xs.Length];
    for (int i = 0; i < xs.Length; i++)
      ys[i] = func(xs[i]);
    return ys;
  }

  static void Main() {
    int[] a = {1, 2, 3, 4, 5};
    double[] b = {1.1, 2.2, 3.3, 4.4, 5.5};
    foreach(int x in Map(n => n * n, a))
      Console.Write("{0} ", x);              // 1 4 9 16 25
    Console.WriteLine("");
    foreach(double x in Map(n => n * n, b))
      Console.Write("{0} ", x);              // 1.21 4.84 10.89 19.36 30.25
    Console.WriteLine("");
  }
}
dotnet run --project sample11
1 4 9 16 25
1.2100000000000002 4.840000000000001 10.889999999999999 19.360000000000003 30.25
$ dotnet script
> Func<int, Func<int, int>> make_adder = n => x => n + x;
> Func<int, int> add10 = make_adder(10);
> add10(1)
11
> add10(20)
30
> Action<string> greeting = mes => Console.WriteLine("hello, {0}", mes);
> greeting("M.Hiroi")
hello, M.Hiroi
> greeting += mes => Console.WriteLine("good by, {0}", mes);
> greeting("M.Hiroi")
hello, M.Hiroi
good by, M.Hiroi

●例外処理

try {

  ...

} catch(例外クラス [引数]) {

  ...

} finally {

  ...

}
$ dotnet script
> class Foo : Exception {};
> try { throw new Foo(); } catch(Foo) { Console.WriteLine("catch Foo"); }
catch Foo
> try { Console.WriteLine("foo"); } finally { Console.WriteLine("oops!")
foo
oops!
> try {throw new Foo();} catch(Foo) {Console.WriteLine("catch Foo");} finally {Console.WriteLine("oops!");}
catch Foo
oops!

●可変長配列

$ dotnet script
> var a = new List<int>();
> for (int i = 0; i < 10; i++) a.Add(i);
> a
List<int>(10) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
> a.Insert(0, -1)
> a
List<int>(11) { -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
> a.RemoveAt(0)
> a
List<int>(10) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
> a.Count
10
> a.Capacity
16
> a.RemoveAt(a.Count - 1);
> a
List<int>(9) { 0, 1, 2, 3, 4, 5, 6, 7, 8 }

●連想配列 (ハッシュ)

$ dotnet script
> var a = new Dictionary<string, int>();
> a["foo"] = 10;
> a["baz"] = 20;
> a["bar"] = 30;
> a["oops"] = 40;
> a
Dictionary<string, int>(4) { { "foo", 10 }, { "baz", 20 }, { "bar", 30 }, { "oops", 40 } }
> a.ContainsKey("foo")
true
> a.ContainsKey("Foo")
false
> a.Keys
Dictionary<string, int>.KeyCollection(4) { "foo", "baz", "bar", "oops" }
> a.Remove("foo")
true
> a
Dictionary<string, int>(3) { { "baz", 20 }, { "bar", 30 }, { "oops", 40 } }
> a.Remove("foo")
false
> a.Remove("Foo")
false

初版 2016 年 9 月 - 11 月
改訂 2022 年 2 月 12 日

Copyright (C) 2016-2022 Makoto Hiroi
All rights reserved.

[ Home | C# ]