xin9le.net

Microsoft の製品/技術が大好きな Microsoft MVP な管理人の技術ブログです。

ラムダ形式メソッド

前回ラムダ形式プロパティを紹介しました。ラムダ式チックなメンバー (Expression-bodied members) は、Visual Studio 14 CTP 2まではプロパティしか実装されていませんでしたが、一昨日 (2014/08/19) リリースされたVisual Studio 14 CTP 3にはメソッド版も搭載されました。

ラムダ形式メソッド

ラムダ形式メソッドは次のように記述します。引数が付いただけで、ラムダ形式プロパティとほとんど変わりません。

public class Point
{
    public uint X { get; };
    public uint Y { get; };
    public double CalculateDistance(Point point) => Sqrt(Pow(X - point.X, 2) + Pow(Y - point.Y, 2));
    public Point(uint x, uint y)
    {
        this.X = x;
        this.Y = y;
    }
}

たったこれだけでメソッドを記述することができます。上記は戻り値を返すタイプですが、もちろん以下のように戻り値をvoidにするも可能です。

class Person
{
    public string Name { get; };
    public void SayHello() => WriteLine("I'm {0}.", Name);
    public Person(string name)
    {
        this.Name = name;
    }
}

これによりメソッドの記述が非常に簡潔になりました。しかし、残念ながら複数のステートメントを持つ形式のラムダ式はサポートされていません。メソッドが1行で完結しない場合は、これまで通りのメソッドを作る必要があります。

public class Point
{
    public uint X { get; };
    public uint Y { get; };
    public double CalculateDistance(Point point) =>  //--- コンパイルエラー
    {
        var dx2 = Pow(X - point.X, 2);
        var dy2 = Pow(Y - point.Y, 2);
        return Sqrt(dx2 + dy2);
    }
    public Point(uint x, uint y)
    {
        this.X = x;
        this.Y = y;
    }
}

逆コンパイル

もはやほぼお約束ですが、ラムダ形式メソッドが既存コードとしてどのように展開されるのかを逆コンパイルで見てみます。

class Point
{
    public uint X
    {
        [CompilerGenerated]
        get { return this.<X>k__BackingField; }
    }
    public uint Y
    {
        [CompilerGenerated]
        get { return this.<Y>k__BackingField; }
    }
    public Point(uint x, uint y)
    {
        this.<X>k__BackingField = x;
        this.<Y>k__BackingField = y;
        base..ctor();
    }
    public double CalculateDistance(Point point)
    {
        return Math.Sqrt(Math.Pow(this.X - point.X, 2.0) + Math.Pow(this.Y - point.Y, 2.0));
    }
}

完全にお察しの通りだと思いますが、ごく普通のメソッドに展開されます。展開された内容を見ると、C# 6.0ベースのコードは、すごくコード量が減ることが分かりますね。