extension-method-slide



extension-method-slide

0 0


extension-method-slide

.NET Framework Extension Method slide

On Github masakura / extension-method-slide

.NET Framework

拡張メソッド

政倉 智

2016/01/23 (土)

[かごべん] LINQ とか勉強会

自己紹介

アジェンダ

本日お話することはこちら!

  • 拡張メソッドって何?
  • 使ったらいけないパターン
  • 使ったほうがいいパターン

拡張メソッドって何?

拡張メソッド

  • LINQ を構成する機能のうちの一つ
  • .NET Framework 3.5 で導入されました
  • さもインスタンスメソッドとして使えるスタティックメソッド

作り方

// 拡張メソッドを宣言する
public static class StringExtension
{
    public static int ToInt32(this String s)
    //                        ~~~~ this とつけるだけ
    {
        return Int32.Parse(s);
    }
}
// スタティックメソッドなのに、インスタンスメソッドのように呼び出せる!
int i = "123".ToInt32();

使ったらいけないパターン

やってはいけない

  • 取るに足らない拡張メソッドを定義することを避けます (特に、ソースコードを所有しているのではない型に対して
    • 引用: .NET クラスライブラリの設計
    • 先程の例がもろにやってはいけない、です
    • マイクロソフトが作ったメソッドに見えてしまう
    • 将来の拡張でメソッドがかぶってしまったり

やみくもに使うことは避けましょう!

使ったほうがいいパターン

ここで使え!

  • 拡張メソッドでクローズジェネリック型を拡張せよ!
    • 引用: More Effective C#
    • T 型を所有している場合、IEnumerable<T> 型に対してインスタンスメソッドよりも拡張メソッドを使います

// IEnumerable<Customer> 型用の拡張メソッド
public static class CustomerExtension
{
    // 男性だけの集合を返す
    public IEnumerable<Customer> Males(this IEnumerable<Customer> customers)
    {
        return customers.Where(c => c.Sex == Sex.Male);
    }

    // 女性だけの集合を返す
    public IEnumerable<Customer> Females(this IEnumerable<Customer> customers)
    {
        return customers.Where(c => c.Sex == Sex.Female);
    }

    // 年齢だけの集合を返す
    public IEnumerable<int> Ages(this IEnumerable<Customer> customers)
    {
        return customers.Select(c => c.Age);
    }
}
// 男性の平均年齢を求める
var age = customers.Males().Ages().Average();

インスタンスメソッドでやろうとすると...

public sealed class CustomerList : List<Customer>
{
    public CustomerList Males() { /* 省略 */ }
    public CustomerList Females() { /* 省略 */ }
    public List<int> Ages() { /* 省略 */ }
}
// 男性の平均年齢を求める
var age = customers.Males().Ages().Average();

できるやん!

でも

インスタンスメソッド版は使い勝手が悪い

List<Customer> 以外のコレクションでは使えない!

// 配列で返ってくると...
Customer[] array = GetCustomers();
// array.Males(); <- 呼び出せない

// HashSet で返ってくると...
HashSet<Customer> hashSet = GetCustomers();
// hashSet.Males(); <- 呼び出せない

// Dictionary で返ってくると...
Dictionary<int, Customer> dictionary = GetCustomers();
// dictionary.Values.Males(); <- 呼び出せない

拡張メソッド版だったら安心!

// 配列で返ってくると...
Customer[] array = GetCustomers();
array.Males(); // <- OK!

// HashSet で返ってくると...
HashSet<Customer> hashSet = GetCustomers();
hashSet.Males(); // <- OK!

// Dictionary で返ってくると...
Dictionary<int, Customer> dictionary = GetCustomers();
dictonary.Values.Males(); // <- OK!

拡張メソッドを使おう!

おすすめ

名前空間を揃える

  • Customer 型と CustomerExtension 型の名前空間を揃える
    • IntelliSense が効きます!
  • アセンブリが別でも名前空間を揃える
using Hoge.Entities
// 名前空間を揃えていないと、別途 using で取り込まないといけない
// using Hoge.Extensions;

public class Foo {
    public void Bar(IEnumerable<Customer> customers) {
        // ここで IntelliSense の候補に拡張メソッドが出ない
        customers.
    }
}

IntelliSense が効かないメソッドは誰も使いません!

まとめ

まとめ

  • LINQ のために導入された拡張メソッドは便利です!
  • 所有していない型の拡張メソッドの使用は避けましょう
  • 所有している型の IEnumerable 型では積極的に使いましょう!
  • 型と拡張メソッドの名前空間は揃えましょう!

参考資料

ご清聴ありがとうございました!

.NET Framework 拡張メソッド 政倉 智 2016/01/23 (土) [かごべん] LINQ とか勉強会