「C#3.0」の編集履歴(バックアップ)一覧に戻る

C#3.0 - (2010/02/12 (金) 15:35:31) のソース

C#3.0ではLINQが追加されました。
それに伴い、LINQの可読性を上げるための機能もC#3.0には追加されています。

&bold(){目次}
#contents()
*暗黙的に型指定されたローカル変数
・明示的に型を指定することなく、ローカル変数を宣言することができようになった
・varキーワードを使用する
・コンパイル時に適切な型が割り当たる
・フィールドでは使用不可
・VB6のVariantと異なり、変数宣言時に初期化が必要
・VB6のVariantと異なり、型変換は出来ない
・型名の冗長さを省く場合や、匿名型を使用した場合に用いる
#highlight(csharp){{
class Program
{
  //フィールドでは使用不可
  //var a = 123;
  static void Main(string[] args)
  {
    var i = 123;
    var d = 12.3M;
    var str = "abc";
    var dt = DateTime.Now;

    //変数宣言時に初期化が必要
    //var b;   

    //型変換は出来ない
    //i = "abc";  

    //型の冗長さを省く場合
    var obj1 = new Myclass();

    //匿名型を使用した場合
    var obj2 = new { Name = "abc" };
  }
}
class Myclass
{
}
}}
*暗黙的に型指定された配列
・newで配列を作成する際、newの後ろの型が省略可能となった
・コンパイル時に{} の中身から適切な型が割り当たる
・複数の型が含まれる場合、コンパイルエラーとなる
#highlight(csharp){{
class Program
{
  static void Main(string[] args)
  {
    var i = new[] { 1, 2, 3, };
    var d = new[] { 1.1, 2.2, 3.3 };
    var str = new[] { "abc", "def", "ghi" };

    //複数の型が含まれる場合、コンパイルエラーとなる
    //var obj = new[] { 1, "abc", 2 };

    //匿名型を使用した場合
    var persons = new[]{
      new{Name = "Taro",Age = 20},
      new{Name = "Jiro",Age = 18}
    };
  }
}
}}
*オブジェクト初期化子
・オブジェクトの初期化が簡潔に記述可能となった
・中カッコ{ }内で初期化を行う
#highlight(csharp){{
class Program
{
  static void Main(string[] args)
  {
    //C#3.0の場合
    var person3 = new Person { Age = 20, Name = "Taro" };

    //C#2.0の場合
    Person person2 = new Person();
    person2.Age = 20;
    person2.Name = "Taro";
  }
}

class Person
{
    public string m_name;
    public int m_age;

    public string Name
    {
        get { return m_name; }
        set { m_name = value; }
    }

    public int Age
    {
        get { return m_age; }
        set { m_age = value; }
    }
}
}}
*コレクション初期化子
・コレクションの初期化が簡潔に記述可能となった
・中カッコ{ }内で初期化を行う
#highlight(csharp){{
class Program
{
  static void Main(string[] args)
  {
    //C#3.0の場合
    var list3 = new List<int> { 1, 2, 3 };
    var dic3 = new Dictionary<string, int>() { { "a", 1 }, { "b", 2 }, { "c", 3 } };

    //C#2.0の場合
    List<int> list2 = new List<int>();
    list2.Add(1);
    list2.Add(2);
    list2.Add(3);
    Dictionary<string, int> dic2 = new Dictionary<string, int>();
    dic2.Add("a", 1);
    dic2.Add("b", 2);
    dic2.Add("c", 3);
  }
}
}}
*自動プロパティ
・プロパティの記述が簡潔に記述可能となった
・コンパイル時、従来のプロパティが自動的に生成される
・get、set 両方を記述する必要がある
・読み取り専用のプロパティを作成するには、プライベートな set を用意する
#highlight(csharp){{
class Person
{
  public string Name { get; set; }
}
}}
上記クラスをコンパイルし[[Reflector for.NET>http://www.red-gate.com/products/reflector/]]を使用し生成ファイルを見ると、以下のフィールド、プロパティが自動生成されていることがわかる
#highlight(csharp){{
internal class Person
{
  // Fields
  private string <Name>k__BackingField;

  // Properties
  public string Name
  {
    get
    {
      return this.<Name>k__BackingField;
    }
    set
    {
      this.<Name>k__BackingField = value;
    }
  }
}
}}
*匿名型
・クラスを別途定義せずにオブジェクト生成が可能となった
・匿名型は、プログラマからはクラス名が不明のためvarキーワードを使用する
・コンパイル時、クラスが自動的に作成される
・同じ名前、同じ型、同じ並び順のプロパティを持つ匿名型は同一のクラスとなる
・主にLINQのselect旬で使用される機能
#highlight(csharp){{
class Program
{
  static void Main(string[] args)
  {
    var obj1 = new { Name = "Taro", Age = 20 };
    var obj2 = new { Name = "Jiro", Age = 18 };

    if (obj1.GetType() == obj2.GetType())
    {
      Console.WriteLine("同じ型");
    }
  }
}
}}
上記クラスをコンパイルし[[Reflector for.NET>http://www.red-gate.com/products/reflector/]]を使用し生成ファイルを見ると、以下のクラスが自動生成されていることがわかる
#highlight(csharp){{
internal sealed class <>f__AnonymousType0<<Name>j__TPar, <Age>j__TPar>
{
  // Fields
  private readonly <Age>j__TPar <Age>i__Field;
  private readonly <Name>j__TPar <Name>i__Field;

  // Methods
  public <>f__AnonymousType0(<Name>j__TPar Name, <Age>j__TPar Age)
  {
    this.<Name>i__Field = Name;
    this.<Age>i__Field = Age;
  }

  // Properties
  public <Age>j__TPar Age
  {
    get
    {
      return this.<Age>i__Field;
    }
  }

  public <Name>j__TPar Name
  {
    get
    {
      return this.<Name>i__Field;
    }
  }
}
}}
*拡張メソッド
・既存クラスを継承することなく、既存クラスにインスタンスメソッドを追加出来る機能
・非ジェネリックのstaticクラス内にてstaticメソッドで宣言する必要がある
・this[[修飾子]]にて、拡張メソッドを追加する型を指定する
・拡張メソッドを含む[[名前空間]]をusing文で指定すると有効となる
#highlight(csharp){{
//拡張メソッドを含む名前空間を指定すると有効となる
using B;

namespace A
{
    class Program
    {
        static void Main(string[] args)
        {
            //拡張メソッドの呼び出し
            "abc".Print();

            //通常のstaticメソッドとしての呼び出しも可能
            StingExtensions.Print("abc");
        }
    }
}

namespace B
{
    static class StingExtensions
    {
        //拡張メソッド
        public static void Print(this string str)
        {
            System.Console.WriteLine(str);
        }
    }
}
}}
・拡張メソッドとインスタンスメソッドが重複した場合、インスタンスメソッドが優先される
#highlight(csharp){{
namespace A
{
    class Program
    {
        static void Main(string[] args)
        {
            X obj = new X();

            //クラスXのMethod()が呼ばれる
            obj.Method();
        }
    }

    class X
    {
        public void Method()
        {
        }
    }

    static class Y
    {
        public static void Method(this X x)
        {
        }
    }
}
}}

*ラムダ式
・ラムダ式は、式とステートメントを含めることができる匿名関数であり、デリゲート型または式ツリー型を作成するために使用される
・[[演算子]] => を使用する
・演算子 => の左辺で入力パラメータを指定し、右辺で式、またはステートメントを指定する
デリゲート型を作成する場合
#highlight(csharp){{
namespace LambdaExpression
{
    delegate int D(int x, int y);

    class Program
    {
        static void Main(string[] args)
        {
            //C#1.0
            //外部メソッドを用意する必要があった
            D d1 = new D(Add);
       
            //C#2.0
            //匿名メソッド使用 { }内に直接記述可能となった
            D d2 = delegate(int x, int y)
            {
                return x + y;
            };

            //C#3.0
            //ラムダ式使用 匿名メソッドより簡略し記述可能となった
      D d3 = (x, y) => x + y;
            //以下の記述も可
            //D d3 = (int x, int y) => { return x + y; };
            //D d3 = (int x, int y) => return x + y;
            //D d3 = (int x, int y) => x + y;
                     
            Console.WriteLine(d1(1, 2));
            Console.WriteLine(d2(1, 2));
            Console.WriteLine(d3(1, 2));
        }

        static int Add(int x, int y)
        {
            return x + y;
        }
    }
}
}}
式ツリー型を作成する場合
#highlight(csharp){{
using System.Linq.Expressions;

namespace LambdaExpression
{
    class Program
    {
        static void Main(string[] args)
        {          
            //ラムダ式をデリゲートに代入すると匿名メソッドとなる
            Func<int, int, int> f = (x, y) => x + y;

            Console.WriteLine(f(1, 2));

            //ラムダ式をExpression式に代入すると式ツリー型となる
            Expression<Func<int, int, int>> e = (x, y) => x + y;
            var bin = (BinaryExpression)e.Body;
            var p1 = (ParameterExpression)bin.Left;
            var p2 = (ParameterExpression)bin.Right;

            Console.WriteLine(bin);
            Console.WriteLine(p1);
            Console.WriteLine(p2);  
        }     
    }
}
}}
*LINQ
・LINQは、Language Integrated Query(統合言語クエリ)の略
・LINQにより、異なる種類のデータに対して統一したクエリ構文でアクセスが可能となった
・LINQにより、C#、VB.NETのコード内にクエリを記述することが出来る
・LINQにより、コンパイル時の型チェック、IntelliSenseの使用がクエリに対し可能となった
・扱えるデータは主に以下となる&br()オブジェクト(LINQ to Objects)&br()XML(LINQ to XML)&br()ADO.NETのDataSet(LINQ to DataSet)&br()SQLサーバのデータベース(LINQ to SQL)&br()ADO.NET Entity Frameworkから提供される概念エンティティ(LINQ to Entities)
C$3.0でのLINQ to Objectsの例
#highlight(csharp){{
class Program
{
    static void Main(string[] args)
    {
        var persons = new[] {                
            new { Name="Taro", Age=20 }, 
            new { Name="Jiro", Age=18 }
        };

        var adults = from person in persons
                     where person.Age >= 20
                     select new { person.Name, person.Age };

        foreach (var adult in adults)
        {
            Console.WriteLine(adult.Name + "," + adult.Age);
        }
    }
}
}}
C#2.0で同様のコードを記述した場合
#highlight(csharp){{
class Program
{
    static void Main(string[] args)
    {
        List<Person> persons = new List<Person>();
        persons.Add(new Person("Taro", 20));
        persons.Add(new Person("Jiro", 18));

        List<Person> adults = new List<Person>();
        foreach (Person person in persons)
        {
            if (person.Age >= 20)
            {
                Person adult = new Person(person.Name, person.Age);
                adults.Add(adult);
            }
        }

        foreach (Person adult in adults)
        {
            Console.WriteLine(adult.Name + "," + adult.Age);
        }
    }
}

class Person
{
    public string m_name;
    public int m_age;

    public Person(string name, int age)
    {
        m_name = name;
        m_age = age;
    }

    public string Name
    {
        get { return m_name; }
        set { m_name = value; }
    }

    public int Age
    {
        get { return m_age; }
        set { m_age = value; }
    }
}
}}
参考
C# 3.0 の概要
[[http://www.microsoft.com/japan/msdn/net/bb308966.aspx>http://www.microsoft.com/japan/msdn/net/bb308966.aspx]]