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

目次

暗黙的に型指定されたローカル変数

  • 明示的に型を指定することなく、ローカル変数を宣言することができようになった
  • varキーワードを使用する
  • コンパイル時に適切な型が割り当たる
  • フィールドでは使用不可
  • VB6のVariantと異なり、変数宣言時に初期化が必要
  • VB6のVariantと異なり、型変換は出来ない
  • 型名の冗長さを省く場合や、匿名型を使用した場合に用いる
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の後ろの型が省略可能となった
  • コンパイル時に{} の中身から適切な型が割り当たる
  • 複数の型が含まれる場合、コンパイルエラーとなる
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}
    };
  }
}
 

オブジェクト初期化子

  • オブジェクトの初期化が簡潔に記述可能となった
  • 中カッコ{ }内で初期化を行う
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; }
    }
}
 

コレクション初期化子

  • コレクションの初期化が簡潔に記述可能となった
  • 中カッコ{ }内で初期化を行う
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 を用意する
class Person
{
  public string Name { get; set; }
}
 
上記クラスをコンパイルしReflector for.NETを使用し生成ファイルを見ると、以下のフィールド、プロパティが自動生成されていることがわかる
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旬で使用される機能
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を使用し生成ファイルを見ると、以下のクラスが自動生成されていることがわかる
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文で指定すると有効となる
//拡張メソッドを含む名前空間を指定すると有効となる
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);
        }
    }
}
 
  • 拡張メソッドとインスタンスメソッドが重複した場合、インスタンスメソッドが優先される
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)
        {
        }
    }
}
 

ラムダ式

  • ラムダ式は、式とステートメントを含めることができる匿名関数であり、デリゲート型または式ツリー型を作成するために使用される
  • 演算子 => を使用する
  • 演算子 => の左辺で入力パラメータを指定し、右辺で式、またはステートメントを指定する
デリゲート型を作成する場合
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;
        }
    }
}
 
式ツリー型を作成する場合
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の使用がクエリに対し可能となった
  • 扱えるデータは主に以下となる
    オブジェクト(LINQ to Objects)
    XML(LINQ to XML)
    ADO.NETのDataSet(LINQ to DataSet)
    SQLサーバのデータベース(LINQ to SQL)
    ADO.NET Entity Frameworkから提供される概念エンティティ(LINQ to Entities)
C$3.0でのLINQ to Objectsの例
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で同様のコードを記述した場合
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; }
    }
}
 
最終更新:2010年02月12日 15:35