拡張メソッド

C# 3.0をはじめよう!!
C# 3.0ってなに?
•.NET Framework 3.5と同時に出荷された
C#の最新バージョン
•以前のバージョンのC# 2.0から様々な
機能拡張が行われた。
•でも、ランタイムであるCLRのバージョン
は変わっていない(コンパイラが変わった)。
どう変わったの?
•型推論
•自動プロパティ
•クラスイニシャライザ
•コレクションイニシャライザ
•ラムダ式
•拡張メソッド
•匿名型
•LINQ
•式ツリー
などの新しい言語仕様、機能が追加された。
何故使うの?
•開発効率が高いから
(型推論、拡張メソッド、ラムダ式、etc)
•.NET Framework 3.5 Client Profileの存在
→ 従来の.NET Framework 2.0よりもインス
トールサイズが小さい(197MB →26.5MB)
•「ラムダ式」とか言いたいから
どうすれば使える?
•開発には「Visual Studio 2008」が必要
•無償版の「Visual C# 2008 Express」でも可
•他にもオープンソースの無償のIDE、
SharpDevelopなんてのもある
•もちろんテキストエディタと
コンパイラ(SDK)だけでも可 (^^
新機能の紹介
•型推論
•自動プロパティ
•クラスイニシャライザ
•コレクションイニシャライザ
•ラムダ式
•拡張メソッド
•匿名型
•LINQ
型推論
•変数宣言の時、型を省略できるようになった。
var s = “hello”;
var i = 1;
// 文字列型
// 数値型
•といっても、型が判断できない時は使えない。
var s;
// コンパイルエラー
•あくまでも、型の記述を省略できるだけなので
var s = “hello”;
S = 1;
// コンパイルエラー
違う型の代入はできない(Variantとかではない)。
型推論
•クラスのフィールド宣言では使えません!!
class Person {
var firstName = “”;
}
// NG
ローカルなスコープ(メソッドの中)でのみ使用可能。
•一番役に立つときは、やっぱりジェネリックの時かな
var strCollection = new List<string>();
var strIntDict = new Dictionary<string, int>();
// こんなん二回も書いてられない
var complex = new Dictionary<string, List<int>>();
型推論
•デリゲートの時は省略できない(当たり前?)。
void DoSomething(string arg) {
// do something
}
var action = DoSomething;
// コンパイルエラー
// デリゲートの型を指定する必要がある
Action<string> action = DoSomething;
•型推論の是非については、色々あるようですが
便利なので、気にせずがんがん使いましょう。
新機能の紹介
•型推論
•自動プロパティ
•クラスイニシャライザ
•コレクションイニシャライザ
•ラムダ式
•拡張メソッド
•匿名型
•LINQ
自動プロパティ
•C# 1.0~2.0の場合
using System;
class Person {
private string firstName;
private string lastName;
public string FirstName {
get { return firstName; }
set { firstName = value; }
}
public string LastName {
get { return lastName; }
set { lastName = value; }
}
}
自動プロパティ
•C# 3.0の場合
using System;
class Person {
public string FirstName {
get;
set;
}
public string LastName {
get;
set;
}
}
get、setを記述するだけでそれに対応したフィールドが
自動生成されるようになった。
自動プロパティ
•でも、getだけとか、setだけとかは無理。
必ず両方宣言する必要がある。
using System;
class Person {
public string FirstName {
get;
// NG
}
public string LastName {
set;
// NG
}
}
使えね~
自動プロパティ
•プロパティの初期値はコンストラクタで設定するしかない。
using System;
class Person {
public string FirstName {
get;
set;
}
public string LastName {
get;
set;
}
public Person() {
this.FirstName = “名無しさん”;
this.LastName = “”;
}
}
新機能の紹介
•型推論
•自動プロパティ
•クラスイニシャライザ
•コレクションイニシャライザ
•ラムダ式
•拡張メソッド
•匿名型
•LINQ
クラスイニシャライザ
•クラスの初期化時にプロパティを設定できるようになった。
var person = new Person {
FirstName = “Kouji”,
LastName = “Yamaguchi”
};
•昔はこんな↓コンストラクタを用意したよね。
public Person(string firstName, string lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
これからは要らないかも!?って、んなわきゃない。
クラスイニシャライザ
•必須のプロパティはコンストラクタの引数で、そうでないプ
ロパティはクラスイニシャライザで設定するという使い分け。
using System;
class Person {
public string FirstName {
get; set;
}
public string LastName {
get; set;
}
public int Age {
get; set;
}
public Person(string firstName, string lastName) {
this.FirstName = firstName;
this.LastName = lastName;
}
}
新機能の紹介
•型推論
•自動プロパティ
•クラスイニシャライザ
•コレクションイニシャライザ
•ラムダ式
•拡張メソッド
•匿名型
•LINQ
コレクションイニシャライザ
•コレクション(配列、リスト)の初期化時に、その要素を
指定できるようになった。
var collection = new List<string>() {
“John”,
“Bob”,
“Kitty”
};
•配列の場合は型を省略することもできる。
// string型の配列
var array = new[] {
“John”,
“Bob”,
“Kitty”
};
コレクションイニシャライザ
•ただし、要素の型は統一する必要がある。
// コンパイルエラー
var array = new[]
“John”,
//
1,
//
true
//
};
{
文字列
数値
真偽値
•ディクショナリの初期化もできるでよ。
var dict = new Dictionary<string, int>() {
{ “John”, 20 },
{ “Bob”, 18},
{ “Kitty”, 12 }
};
コレクションイニシャライザ
•ちなみにコレクションイニシャライザで初期化できる
クラスの条件は、
•System.Collections.IEnumerableを実装している
•引数を一つ以上とるpublicなAddメソッドを実装している。
class FakeCollection : IEnumerable {
public void Add(string value) {
}
IEnumerator IEnumerable.GetEnumerator() { yield break; }
}
var c = new FakeCollection {
“Hoge”,
“Fuga”
};
これが成立する。
新機能の紹介
•型推論
•自動プロパティ
•クラスイニシャライザ
•コレクションイニシャライザ
•ラムダ式
•拡張メソッド
•匿名型
•LINQ
ラムダ式
•匿名メソッドってあったよね?
Action<string> showMsg = delegate(string msg) {
Console.WriteLine(msg);
};
showMsg(“Hello, World”);
名前の無いメソッドを定義できるやつ。
•これが、こんな感じ↓で書けるようになった。
Action<string> showMsg = (msg) => Console.WriteLine(msg);
showMsg(“Hello, World”);
ラムダ式
•引数が一つの場合は、引数の括弧を省略できる。
Action<string> showMsg = msg => Console.WriteLine(msg);
•引数が無い場合は、括弧だけでOK。
Action newLine = () => Console.WriteLine();
•処理が一行の場合は返り値を返すのにreturnはいらない。
Func<string> getMsg = () => “Hello, World”;
•処理が複数行に渡る場合は、returnが必要になる。
Func<bool, string> getMsg = (value) => {
return value == “Hoge”;
};
ラムダ式
•すごい便利ですね!!
var list = new List<string> {
“John”,
“Bob”,
“Kitty”
};
// 簡潔に記述できる。
list.ForEach(s => Console.WriteLine(s));
•もちろんクロージャとしても機能する。
var i = 0;
Action increment = () => i++;
// iがインクリメントされる。
increment()
新機能の紹介
•型推論
•自動プロパティ
•クラスイニシャライザ
•コレクションイニシャライザ
•ラムダ式
•拡張メソッド
•匿名型
•LINQ
拡張メソッド
•今までちょっとした便利機能はユーティリティクラス
(staticなメソッドのみのクラス)を作って実装していた。
public static class StringUtils {
// 指定した文字列の末尾の文字を取得するメソッド
public static char Last(string value) {
return value[value.Length - 1];
}
}
// e
Console.WriteLine(StringUtils.Last(“Hoge”));
•これでも十分事は足りるけど、やっぱり本当はstringクラス
に「Last」というメソッドが欲しい。
•そこで「拡張メソッド」ですよ。
拡張メソッド
•thisキーワードを使って引数を定義すると・・・
public static class StringUtils {
// 指定した文字列の末尾の文字を取得するメソッド
public static char Last(this string value) {
return value[value.Length - 1];
}
}
// e
Console.WriteLine(“Hoge”.Last());
その引数の型のメソッドのように振る舞う事ができる。
•これは基本ライブラリのクラス(stringとかintとか)に
メソッドを追加できる(ように見える)という事。
•ちなみに、拡張メソッドを定義するクラスは必ず
staticにする必要がある。
拡張メソッド
•便利な拡張メソッドとして、
最大値・最小値・平均値を求めるもの
var nums = new[] {
1, 5, 2, 4, 10, 16, 30, 88
};
Console.WriteLine(“最大値: ” + nums.Max());
Console.WriteLine(“最小値: ” + nums.Min());
Console.WriteLine(“平均値: ” + nums.Average());
•オブジェクトの配列からディクショナリに変換するもの
var objs = new[] {
new Person(“John”, “Sykes”),
new Person(“Yngwei”, “Malmsteen”),
new Person(“Ritchie”, “Blackmore”)
}
var dict = objs.ToDictionary(o => o.FirstName, o => o.LastName);
なんてのがある。
拡張メソッド
•拡張メソッドはインターフェースにも定義できるので、
interface IHoge { }
interface IFuga { }
static class HogeExtension {
public static void HelloHoge(this IHoge hoge) {
}
}
static class FugaExtension {
public static void HelloFuga(this IFuga fuga) {
}
}
class HogeFuga : IHoge, IFuga {
}
var o = new HogeFuga();
o.HelloHoge();
o.HelloFuga();
これを利用すると多重継承、Mix-In(みたいなの)
ができるようになる。
新機能の紹介
•型推論
•自動プロパティ
•クラスイニシャライザ
•コレクションイニシャライザ
•ラムダ式
•拡張メソッド
•匿名型
•LINQ
匿名型
•名前の無い、匿名のクラスを定義(プロパティのみ)できる。
var obj = new {
Row = 1,
Column = 1,
Value = “John”
};
// Row = 1, Column = 1, Value = John
Console.WriteLine(
“Row = {0}, Column = {1}, Value = {2}”,
// プロパティとしてアクセスできる。
obj.Row, obj.Column, obj.Value
);
ただし、ローカルスコープ(メソッド内)でしか使えない。
•普通は一時的なデータの入れ物として使う。
今までディクショナリとかインナークラスとかでやってた事
が、これで少しだけ楽になる。
匿名型
•メソッドは定義できないけど、デリゲートのプロパティを
定義すればメソッドのように振る舞える。
var obj = new {
DoSomething = (Action<string>)(msg => Console.WriteLine(msg))
};
obj.DoSomething();
なにかに使えるかも!?
匿名型
•例えば、↓こんなメソッドがあった場合
void DoSomething(IDictionary<string, object> keyValues) { }
ディクショナリを初期化して渡すのって、結構だるいよね。
DoSomething(new Dictionary<string, object> {
{ “Product”, “Hoge” },
{ “Price”, 100 }
});
•これが匿名クラスで指定できたら、楽じゃね?
DoSomething(new {
Product = “Hoge”,
Price = 100
});
匿名型
•そんな時は、↓こんなクラスを作れば、
static class ObjectExtension {
// object型をIDictionary<string, object>型に変換する。
public static IDictionary<string, object> ToDict(this object obj) {
var tp = obj.GetType();
var props = tp.GetProperties(
BindingFlags.Instance | BindingFlags.Public |
BindingFlags.GetProperty
);
return props.ToDictionary(
p => p.Name,
p => tp.InvokeMember(
p.Name, BindingFlags.GetProperty, null, obj, null
)
);
}
}
匿名型
•↓こんな風に書けます。
DoSomething(new {
Product = “Hoge”,
Price = 100
}.ToDict());
新機能の紹介
•型推論
•自動プロパティ
•クラスイニシャライザ
•コレクションイニシャライザ
•ラムダ式
•拡張メソッド
•匿名型
•LINQ
LINQ
•Language Integrated Query(統合言語クエリ)
var array = new[] {
“John”,
“Bob”,
“Sandy”
};
var query = from o in array
where o.Contains(“o”)
select o;
// John
// Bob
foreach(var o in query) Console.WriteLine(o);
コレクション(リスト、配列)に対して、SQLのようなクエリ
言語で検索がかけられる。
LINQ
•LINQの特徴は共通のクエリ言語を使って、
異なる種類のデータソースに対して検索が行えること。
例えば、
オブジェクトのコレクションに対して検索を行う
•LINQ to Object
SQLサーバーに対して検索を行う
•LINQ to SQL (DLINQ)
XMLドキュメントに対して検索を行う
•LINQ to XML (XLINQ)
が用意されている。
LINQ
•LINQのコンパイル時の処理フロー
var query = from o in array
where o.Contains(“o”)
select o;
•演算子が対応する拡張メソッドに置き換わる。
var query = array.Where(o => o.Contains(“o”)).Select(o => o);
•プロバイダ毎のクエリに変換される。
LINQ to Object
LINQ to SQL
LINQ to XML
SQLクエリ
XPathクエリ
LINQ
•LINQで使用できる演算子
from [要素] in [コレクション]
where [条件]
join [要素] in [コレクション] on [左辺] equals [右辺]
group [要素] by [キー]
order by [キー] [ascending|decending]
select [要素]
•LINQに対応している拡張メソッド
Single, SingleOrDefault
First, FirstOrDefault
Last, LastOrDefault
Count
Take, TakeWhile
Skip, SkipWhile
Max, Min, Sum
(DLINQのデモ)
まとめ
•C# 3.0の新しい機能は全てLINQの為にある。
•LINQに魅力を感じるかどうかがC# 3.0を導入するかどうか
のポイントになる。
•LINQを使いこなせなければ、C# 3.0を使うメリットはあま
り無いかも?
•まぁ、何にせよ開発効率とおもしろさは間違いなく向上する
ので、やって損は無い。
•とりあえず皆さんC# 3.0をはじめましょう
\(^o^)/
(おわり)