C# 6.0 Preview 小小 小小小 2014-08-30
Nov 12, 2014
C# 6.0 Preview
小島 富治雄2014-08-30
自己紹介
• 小島 富治雄
• @Fujiwo• 福井コンピュータアーキテクト株式会社
• Microsoft MVP C# (2005-2015)• プログラミング C# - 翔ソフトウェア
(Sho's)• http://blog.shos.info
•スライドhttp://1drv.ms/1vcTMOp•サンプル コード
http://1drv.ms/1vcTNSv
本日の資料
1. C# 6.0 とは2. C# 6.0 Demo3. C# 6.0 考察
アジェンダ
C#6.0 とは
C# の進化
6
C# 1.0 C# 2.0C# 3.0C# 4.0C# 5.0C# 6.0
オブジェクト指向ジェネリック
関数型dynamic
非同期Roslyn
7
C# におけるパラダイムの追加の歴史
delegate
C# 1.X C# 2.0 C# 3.0 C# 4.0 C# 5.0
class
手続き型 関数型
ラムダ式
LINQ
型推論
ジェネリック
拡張メソッド
動的型付け
dynamic
非同期
async/await
オブジェクト指向
Parallel
メタプログラミング
Roslyn
C# 6.0
.NET Compiler Platform ("Roslyn")
•次世代の C# (VB) コンパイラー• オープンソース
•コード分析 ( 等の ) API
.NET Compiler Platform (“Roslyn”)での C# 6.0 の現状
• .NET Compiler Platform ("Roslyn")• http://roslyn.codeplex.com
• ++C++; // 未確認飛行 C ブログ• .NET Compiler Platform (Roslyn) Preview |
++C++; // 未確認飛行 C ブログ• https://ufcpp.wordpress.com/2014/04/04/net-
compiler-platform-roslyn-preview/• C# before/after• https://ufcpp.wordpress.com/2014/04/06/c-be
foreafter/
C# 6.0 の紹介記事 ( 日本語 )
• Try! C# vNext - xin9le.net• http://xin9le.net/csharp-vnext
C# 6.0 の紹介記事 ( 日本語 )
• C# 6.0 言語プレビュー - MSDN マガジン May 2014• http://msdn.microsoft.com/ja-jp/magazine
/dn683793.aspx
C# 6.0 の紹介記事 ( 日本語 )
C# vNext ( 以下 C# 6.0 。ただし、非公式名称なので注意してください ) をすぐに使用する予定がなくても、その機能を知れば、今すぐ導入する価値があると考えるでしょう。
• Briefly exploring C# 6 new features - CodeProject• http://www.codeproject.com/Articles/8087
32/Briefly-exploring-Csharp-new-features
C# 6.0 の紹介記事 ( 英語 )
.NET Compiler Platform (“Roslyn”)での C# 6.0 の現状
• Language Feature Status - .NET Compiler Platform ("Roslyn")• http
://roslyn.codeplex.com/wikipage?title=Language%20Feature%20Status
• C# feature descriptions• http://
www.codeplex.com/Download?ProjectName=roslyn&DownloadId=894944
Language Feature Status• Exists: Already shipped in previous release• Done: Implemented for this release• Planned: Intended for this release• Maybe: Possibly intended for this release• Withdrawn: Probably not in this release• No: Not intended for this release• N/A: Not meaningful for this language• http://
roslyn.codeplex.com/wikipage?title=Language%20Feature%20Status
Feature Example C# VB Primary constructors class Point(int x, int y) { … } Done Maybe
Auto-property initializers public int X { get; set; } = x; Done Exists
Getter-only auto-properties public int Y { get; } = y; Done Done
Using static members
using System.Console; … Write(4); Done Exists
Dictionary initializer
new JObject { ["x"] = 3, ["y"] = 7 } Done Planned
Indexed member initializer
new JObject { $x = 3, $y = 7 } Withdrawn Planned
Indexed member access
c.$name = c.$first + " " + c.$last; Withdrawn Exists
Declaration expressions int.TryParse(s, out var x); Done Maybe
Await in catch/finally
try … catch { await … } finally { await … } Done Planned
Exception filters catch(E e) if (e.Count > 5) { … } Done Exists
Typecase Select Case o : Case s As String : … No Maybe
Guarded cases Select Case i : Case Is > 0 When i Mod 2 = 0 No Maybe
Partial modules Partial Module M1 N/A Done
Partial interfaces Partial Interface I1 Exists Done
Multiline string literals "Hello<newline>World" Exists Done
Year-first date literals Dim d = #2014-04-03# N/A Done
Binary literals 0b00000100 Planned Planned Digit separators 0xEF_FF_00_A0 Planned Planned
Feature Example C# VB Line continuation comments
Dim addrs = From c in Customers ' comment N/A Done
TypeOf IsNot If TypeOf x IsNot Customer Then … N/A Done
Expression-bodied members
public double Dist => Sqrt(X * X + Y * Y); Planned No
Event initializers
new Customer { Notify += MyHandler }; Planned Planned
Null propagation customer?.Orders?[5]?.$price Done Planned Semicolon operator
(var x = Foo(); Write(x); x * x) Maybe Maybe
Private protected
private protected string GetId() { … } Withdrawn Withdrawn
Params IEnumerable
int Avg(params IEnumerable<int> numbers) { … }
Planned Planned
Constructor Inference new Tuple(3, "three", true); Maybe Maybe
String interpolation
"\{p.First} \{p.Last} is \{p.Age} years old." Maybe Maybe
TryCast for nullable Dim x = TryCast(u, Integer?) Exists Planned
Delegate combination with +
d1 += d2 Exists Planned
Implicit implementation
Class C : Implicitly Implements I Exists Planned
nameof operator string s = nameof(Console.Write); Exists Planned
Strict modules Strict Module M Exists Planned
Faster CInt Dim x = CInt(Math.Truncate(d)) | Exists Planned
#pragma #Disable Warning BC40008 Exists Planned
Checked and Unchecked blocks Checked : x += 1 : End Checked Exists Maybe
Field targets on autoprops
<Field: Serializable> Property p As Integer Planned Planned
Last edited Tue at 8:23 AM by madst, version 28
• Visual Studio “14” CTP 3 Released• http://
blogs.msdn.com/b/visualstudio/archive/2014/08/18/visual-studio-14-ctp-3-released.aspx
Visual Studio “14” CTP 3 ( 最新 )
•~ .csproj ファイル に 1 行を追加
C#6.0 を試すとき
<?xml version="1.0" encoding="utf-8"?><Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <PropertyGroup> …… <LangVersion>experimental</LangVersion> </PropertyGroup> ……</Project>
C# 6.0 Demo
静的メンバーへの簡易アクセス (Using static)using System.Console; // 静的メンバーへの簡易アクセス (Using static)
using System.Math; // 静的メンバーへの簡易アクセス (Using static)
using System.Linq.Enumerable; // 静的メンバーへの簡易アクセス (Using static)
class Program
{
static void Main()
{
// 静的メンバーへの簡易アクセス (Using static)
WriteLine("Hello world!");
var root2 = Sqrt(2.0);
// 静的メンバーへの簡易アクセス : 拡張メソッド
var data = new[] { 2, 4, -1, 3, 0 };
var odd = Where(data, number => number % 2 != 0); // Ok
//var even = data.Where(i => i % 2 == 0); // Error, using System.Linq が無いのでスコープ外
}
}
参考 : beforeusing System;
using System.Linq;
class Program
{
static void Main()
{
Console.WriteLine("Hello world!");
var root2 = Math.Sqrt(2.0);
// 静的メンバーへの簡易アクセス : 拡張メソッド
var data = new[] { 2, 4, -1, 3, 0 };
var odd = Enumerable.Where(data, number => number % 2 != 0);
var even = data.Where(i => i % 2 == 0);
}
}
プライマリ コンストラクタusing System;
// プライマリ コンストラクタ (Primary constructors)
class Employee(int number, string name) // Parameters on classes
{
{ // プライマリ コンストラクタ本体
if (number < 0 || string.IsNullOrWhiteSpace(name))
throw new ArgumentOutOfRangeException();
}
// Explicit constructors
public Employee(string name)
: this(1, name) // プライマリ コンストラクタを呼ぶ
{ }
// Getter のみの自動実装プロパティ (Getter-only auto-properties)
// 自動実装プロパティ初期化子 (Initializers for auto-properties)
public double Number { get; } = number;
public string Name { get; } = name ;
}
class Staff(int number, string name, DateTime hiredDate)
: Employee(number, name) // ベース クラスのコンストラクタを呼ぶ
{
DateTime hiredDate_ = hiredDate; // 初期化のスコープ
//void TemporaryFunction()
//{
// var hiredDate_ = hiredDate; // NG
//}
}
class Program
{
static void Main()
{
var employee = new Employee(1, " 山田太郎 ");
var staff = new Staff (1, " 福井太郎 ", DateTime.Now);
}
}
参考 : beforeusing System;
class Employee
{
public Employee(int number, string name)
{
if (number < 0 || string.IsNullOrWhiteSpace(name))
throw new ArgumentOutOfRangeException();
Number = number;
Name = name ;
}
public Employee(string name)
: this(1, name)
{ }
public int Number { get; private set; }
public string Name { get; private set; }
}
class Staff : Employee
{
DateTime hiredDate_;
public Staff(int number, string name, DateTime hiredDate)
: base(number, name) // ベース クラスのコンストラクタを呼ぶ
{
this.hiredDate_ = hiredDate;
}
}
class Program
{
static void Main()
{
var employee = new Employee(1, " 山田太郎 ");
var staff = new Staff (1, " 福井太郎 ", DateTime.Now);
}
}
Expression-bodied membersusing System.Console; // 静的メンバーへの簡易アクセス (Using static)
using System.Math; // 静的メンバーへの簡易アクセス (Using static)
class Program
{
static void Main()
{
var point1 = new Point();
var point2 = new Point(1.1, 2.2);
(point1 + point2).Print();
}
}
class Point(double x = 0.0, double y = 0.0) // プライマリ コンストラクタ (Primary constructors)
{
public double X { get; } = x; // Getter のみの自動実装プロパティ (Getter-only auto-properties)/ 自動実装プロパティ初期化子 (Initializers for auto-properties)
public double Y { get; } = y; // Getter のみの自動実装プロパティ (Getter-only auto-properties)/ 自動実装プロパティ初期化子 (Initializers for auto-properties)
// Expression bodies on property-like function members
public double Length => Sqrt(X * X + Y * Y); // 静的メンバーへの簡易アクセス (Using static)
// Expression bodies on method-like members
public static Point operator +(Point point1, Point point2)
=> new Point(point1.X + point2.X, point1.Y + point2.Y);
// Expression bodies on method-like members (void)
public void Print() => WriteLine("({0}, {1})", X, Y); // 静的メンバーへの簡易アクセス (Using static)
// Expression bodied indexers
// public double this[int index] => index == 0 ? X : Y; // not yet
}
参考 : beforeusing System;
class Program
{
static void Main()
{
var point1 = new Point(-0.1, 3.8);
var point2 = new Point(1.1, 2.2);
(point1 + point2).Print();
}
}
class Point
{
public Point(double x = 0.0, double y = 0.0)
{
X = x;
Y = y;
}
public double X { get; private set; }
public double Y { get; private set; }
public double Length
{
get { return Math.Sqrt(X * X + Y * Y); }
}
public static Point operator +(Point point1, Point point2)
{ return new Point(point1.X + point2.X, point1.Y + point2.Y); }
public void Print()
{ Console.WriteLine("({0}, {1})", X, Y); }
public double this[int index]
{
get { return index == 0 ? X : Y; }
}
}
struct の場合using System.Console; // 静的メンバーへの簡易アクセス (Using static)
// プライマリ コンストラクタ (Primary constructors)
public struct Tally(int count, int sum) // Parameters on structs
{
// Getter のみの自動実装プロパティ (Getter-only auto-properties)
// 自動実装プロパティ初期化子 (Initializers for auto-properties)
public int Count { get; } = count;
public int Sum { get; } = sum ;
// Expression bodies on property-like function members
public double Average => (double)Sum / Count;
}
class Program
{
static void Main()
{
var tally = new Tally(10, 500);
WriteLine(tally.Average); // 静的メンバーへの簡易アクセス (Using static)
}
}
参考 : beforeusing System;
public struct Tally
{
int count;
int sum ;
public int Count { get { return count; } }
public int Sum { get { return sum ; } }
public Tally(int count, int sum)
{
this.count = count;
this.sum = sum ;
}
public double Average
{
get { return (double)Sum / Count; }
}
}
class Program
{
static void Main()
{
var tally = new Tally(10, 500);
Console.WriteLine(tally.Average);
}
}
変数宣言式 (Declaration expressions)using System.Console; // 静的メンバーへの簡易アクセス (Using static)
using System.Linq;
class Program
{
static void Sub(object item)
{
if ((var text = item as string) != null)
WriteLine(text); // 静的メンバーへの簡易アクセス (Using static)
}
static void Main()
{
// 変数宣言式 (Declaration expressions)
if (int.TryParse("123", out int number))
WriteLine(number); // 静的メンバーへの簡易アクセス (Using static)
var texts = new[] { "123", "a123", "-34", "Q", "123" };
var sum1 = texts.Select(text => int.TryParse(text, out int number) ? number : 0).Sum();
WriteLine(sum1); // 静的メンバーへの簡易アクセス (Using static)
var sum2 = texts.Select(text => int.TryParse(text, out var number) ? number : 0).Sum();
WriteLine(sum2); // 静的メンバーへの簡易アクセス (Using static)
Sub("ABC");
}
}
参考 : beforeusing System.Console; // 静的メンバーへの簡易アクセス (Using static)
using System.Linq;
class Program
{
static void Sub(object item)
{
if ((var text = item as string) != null)
WriteLine(text); // 静的メンバーへの簡易アクセス (Using static)
}
static void Main()
{
// 変数宣言式 (Declaration expressions)
if (int.TryParse("123", out int number))
WriteLine(number); // 静的メンバーへの簡易アクセス (Using static)
var texts = new[] { "123", "a123", "-34", "Q", "123" };
var sum1 = texts.Select(text => int.TryParse(text, out int number) ? number : 0).Sum();
WriteLine(sum1); // 静的メンバーへの簡易アクセス (Using static)
var sum2 = texts.Select(text => int.TryParse(text, out var number) ? number : 0).Sum();
WriteLine(sum2); // 静的メンバーへの簡易アクセス (Using static)
Sub("ABC");
}
}
null 伝搬演算子 (Null-conditional operators)using System.Console; // 静的メンバーへの簡易アクセス (Using static)
class Person
{
public string Name { get; set; }
}
class Program
{
static void Main()
{
// null 伝搬演算子 (Null-conditional operators)
Person person = null;
var name1 = person?.Name?.Trim() ?? "anonymous";
WriteLine(name1); // 静的メンバーへの簡易アクセス (Using static)
Person[] people = null;
var name2 = people?[0]?.Name?.Trim() ?? "anonymous";
WriteLine(name2); // 静的メンバーへの簡易アクセス (Using static)
}
}
参考 : beforeusing System;
class Person
{
public string Name { get; set; }
}
class Program
{
static void Main()
{
Person person1 = null;
if (person1 != null) {
var name = person1.Name;
if (name != null) {
name = name.Trim();
Console.WriteLine(name);
}
}
Person[] people = null;
if (people != null) {
var person2 = people[0];
if (person2 != null) {
var name = person2.Name;
if (name != null) {
name = name.Trim();
Console.WriteLine(name);
}
}
}
}
}
catch/finally での await (Await in catch/finally)using System;
using System.Console; // 静的メンバーへの簡易アクセス (Using static)
using System.Threading.Tasks;
// catch/finally での await (Await in catch/finally)
class Program
{
static async Task DoSomethingCanFailAsync()
{
await Task.Delay(1000);
if (true)
throw new Exception("Error!");
}
static async Task ErrorFunctionAsync(string errorMessage)
{
await Task.Delay(1000);
WriteLine(errorMessage); // 静的メンバーへの簡易アクセス (Using static)
}
static async Task Sub()
{
try {
await DoSomethingCanFailAsync();
} catch (Exception ex) {
await ErrorFunctionAsync(ex.Message);
}
}
static void Main()
{
Sub().Wait();
}
}
参考 : beforeusing System;
using System.Threading.Tasks;
class Program
{
static async Task DoSomethingCanFailAsync()
{
await Task.Delay(1000);
if (true)
throw new Exception("Error!");
}
static async Task ErrorFunctionAsync(string errorMessage)
{
await Task.Delay(1000);
Console.WriteLine(errorMessage);
}
{
Exception exception = null;
try {
await DoSomethingCanFailAsync();
} catch (Exception ex) {
exception = ex;
}
if (exception != null)
await ErrorFunctionAsync(exception.Message);
}
static void Main()
{
Sub().Wait();
}
}
例外フィルター (Exception filters)using System;
using System.Console; // 静的メンバーへの簡易アクセス (Using static)
// プライマリ コンストラクタ (Primary constructors)
class MyException(MyException.Type state = MyException.Type.Normal)
: Exception
{
public enum Type
{ Normal, Abnormal }
public Type State { get; } = state; // Getterのみの自動実装プロパティ (Getter-only auto-properties)/ 自動実装プロパティ初期化子 (Initializers for auto-properties)
}
class Program
{
static void Sub()
{
throw new MyException(MyException.Type.Abnormal);
}
static void Main()
{
// 例外フィルター (Exception filters)
try {
Sub();
} catch (MyException ex) if (ex.State == MyException.Type.Abnormal) { // 例外フィルター (Exception filters)
WriteLine("catch block: Abnormal."); // 静的メンバーへの簡易アクセス (Using static)
} catch (MyException ex) {
WriteLine("catch block: Normal." ); // 静的メンバーへの簡易アクセス (Using static)
}
}
}
参考 : beforeusing System;
class MyException : Exception
{
public enum Type
{ Normal, Abnormal }
public MyException(MyException.Type state = MyException.Type.Normal)
{
State = state;
}
public Type State { get; private set; }
}
class Program
{
static void Sub()
{
throw new MyException(MyException.Type.Abnormal);
}
static void Main()
{
try {
Sub();
} catch (MyException ex) {
if (ex.State == MyException.Type.Abnormal)
Console.WriteLine("catch block: Abnormal.");
else
Console.WriteLine("catch block: Normal." );
}
}
}
nameof 演算子 (Nameof expressions)using System.Console; // 静的メンバーへの簡易アクセス (Using static)
using System.ComponentModel;
class Program
{
static void Main()
{
var person = new Person { FirstName = "Steve", LastName = "Ballmer" };
person.PropertyChanged += (sender, e) => WriteLine(string.Format("{0} has changed.", e.PropertyName));
person.FirstName = "Satya" ;
person.FirstName = "Nadella";
}
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
nameof 演算子 (Nameof expressions)class Person : ViewModelBase
{
string firstName = string.Empty;
public string FirstName
{
get { return firstName; }
set {
if (value != firstName) {
firstName = value;
RaisePropertyChanged(nameof(FirstName)); // nameof演算子 (Nameof expressions)
RaisePropertyChanged(nameof(FullName )); // nameof演算子 (Nameof expressions)
}
}
}
string lastName = string.Empty;
public string LastName
{
get { return lastName; }
set {
if (value != lastName) {
lastName = value;
RaisePropertyChanged(nameof(LastName)); // nameof 演算子 (Nameof expressions)
RaisePropertyChanged(nameof(FullName)); // nameof 演算子 (Nameof expressions)
}
}
}
public string FullName
{
get { return string.Format("{0} {1}", FirstName, LastName); }
}
}
参考 : before その 1using System;
using System.ComponentModel;
class Program
{
static void Main()
{
var person = new Person { FirstName = "Steve", LastName = "Ballmer" };
person.PropertyChanged += (sender, e) => Console.WriteLine(string.Format("{0} has changed.", e.PropertyName));
person.FirstName = "Satya";
person.FirstName = "Nadella";
}
}
class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
参考 : before その 1 string firstName = string.Empty;
string lastName = string.Empty;
public string FirstName
{
get { return firstName; }
set
{
if (value != firstName) {
firstName = value;
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("FirstName"));
PropertyChanged(this, new PropertyChangedEventArgs("FullName" ));
}
}
}
}
public string LastName
{
get { return lastName; }
set
{
if (value != lastName) {
lastName = value;
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("LastName"));
PropertyChanged(this, new PropertyChangedEventArgs("FullName"));
}
}
}
}
public string FullName
{
get { return string.Format("{0} {1}", FirstName, LastName); }
}
}
参考 : before その 2using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
class Program
{
static void Main()
{
var person = new Person { FirstName = "Steve", LastName = "Ballmer" };
person.PropertyChanged += (sender, e) => Console.WriteLine(string.Format("{0} has changed.", e.PropertyName));
person.FirstName = "Satya";
person.FirstName = "Nadella";
}
}
public static class PropertyChangedEventHandlerExtensions
{
public static void Raise(this PropertyChangedEventHandler onPropertyChanged, object sender, [CallerMemberName] string propertyName = "")
{
if (onPropertyChanged != null)
onPropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
}
public static void Raise<PropertyType>(this PropertyChangedEventHandler onPropertyChanged, object sender, Expression<Func<PropertyType>> propertyExpression)
{ onPropertyChanged.Raise(sender, propertyExpression.GetMemberName()); }
static string GetMemberName<MemberType>(this Expression<Func<MemberType>> expression)
{ return ((MemberExpression)expression.Body).Member.Name; }
}
参考 : before その 2class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
string firstName = string.Empty;
string lastName = string.Empty;
public string FirstName
{
get { return firstName; }
set {
if (value != firstName) {
firstName = value;
PropertyChanged.Raise(this);
PropertyChanged.Raise(this, () => FullName);
}
}
}
public string LastName
{
get { return lastName; }
set {
if (value != lastName) {
lastName = value;
PropertyChanged.Raise(this);
PropertyChanged.Raise(this, () => FullName);
}
}
}
public string FullName
{
get { return string.Format("{0} {1}", FirstName, LastName); }
}
}
その他 (not yet)using System.Collections.Generic;
using System.Console; // 静的メンバーへの簡易アクセス (Using static)
class Program
{
static void Main()
{
// Index initializers
// Note: Index initializers have been previously previewed but do not work in the current CTP.
var numberNames = new Dictionary<string, string>
{
{ " 二 ", "two" },
{ " 三 ", "three" },
{ " 五 ", "five" }
};
//var numberNames = new Dictionary<string, string> {
// [" 二 "] = "two" ,
// [" 三 "] = "three",
// [" 五 "] = "five"
//};
//// Indexed member initializer (Withdrawn)
//var numberNames = new Dictionary<string, string> {
// $ 二 = "two" ,
// $ 三 = "three",
// $ 五 = "five"
//};
// Indexed member access (Withdrawn)
var numberName = numberNames[" 三 "];
// var numberName = numberNames.$ 三 ;
}
}
その他 (not yet)using System.Collections.Generic;
using System.Console; // 静的メンバーへの簡易アクセス (Using static)
class Program
{
static void Main()
{
// Binary literals (Planned)
// var bits = 0b00000100;
// Digit separators (Planned)
// var bits = 0b0010_1110;
// var hex = 0x00_2E;
// var dec = 1_234_567_890;
// Event initializers (Planned)
// new Customer { Notify += MyHandler };
// Params IEnumerable (Planned)
//int Avg(params IEnumerable<int> numbers) { … }
// String interpolation (Maybe)
// "\{p.First} \{p.Last} is \{p.Age} years old.“
}
}
C# 6.0 考察
これらははたして言語として正当な進化なのか ?
進化には理由がある何が進化を起こさせているのか
C# 6.0 の進化の理由は ?
どんな問題をどういうアプローチで
解こうとしているのか ?
テクノロジーの進化に対するいつもの問
他の言語の進化と比べてみよう
• Java 8のすべて - InfoQhttp://www.infoq.com/jp/news/2013/09/everything-about-java-8
• Everything about Java 8 - TechEmpower Bloghttp://www.techempower.com/blog/2013/03/26/everything-about-java-8/
• Java8 でのプログラムの構造を変える Optional - きしだのはてなhttp://d.hatena.ne.jp/nowokay/20130524
• Java8 とC# - 猫と C#について書く matarillo の雑記http://d.hatena.ne.jp/matarillo/20131217/p1
• C# 使いから見てうらやましい Java8 の default 実装の使い方 - ぐるぐる~http://bleis-tift.hatenablog.com/entry/java8-default-impl
• LINQ to Objects と Java8-Stream API の対応表 – Qiitahttp://qiita.com/amay077/items/9d2941283c4a5f61f302
Java8 との比較
•デフォルトメソッド
• Optional
(C#er としては、基本的に羨ましくないが )Java8 のちょっとだけ羨ましいところ
Java8 のデフォルトメソッド
public interface MyInterface {
void method1();
default void method2() {
System.out.println("MyInterface.method2 has called.");
}
}
public class MyClass implements MyInterface {
@Override
public void method1() {
System.out.println("MyClass.method1 has called.");
}
}
C# での例 :// 1.X の頃 の IEnumerable
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
// 2.0 以降ジェネリクスに
// でも互換性が必要なので……
public interface IEnumerator<out T> : IDisposable, IEnumerator
{
T Current { get; }
}
public interface IEnumerable<out T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
結果、こんな残念なことに…… ( 悲報 )class MyCollection : IEnumerable<int>{ public IEnumerator<int> GetEnumerator() { yield return 2; yield return 3; yield return 5; }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }}
技術的負債 !
今更、仕方ない ?
Java8 の default が使えれば…
public interface IEnumerable<out T> : IEnumerable{ IEnumerator<T>
GetEnumerator();
default IEnumerator GetEnumerator() { return GetEnumerator(); }}
class MyCollection :
IEnumerable<int>{ public IEnumerator<int>
GetEnumerator() { yield return 2; yield return 3; yield return 5; }}
Java8 の Optional// こんなコードが…
void outoutAsName(String text)// text は null かも知れな
いとする
{ if (text != null) { String name = normalize(text);
// normalize は null を返す可能性があるとする
if (name != null && name.length() > 3) output(name); }}
Java8 の Optional// Optional を使うと…
void outoutAsName(String text)// text は null かも
知れないとする
{Optional.ofNullable(name)
.map(name -> normalize(name)) .filter(name -> text.length()
> 3) .ifPresent(name -> output(name));}
• C#6.0 の「 null 伝搬演算子」と似ている
•が、違う• Optional の方がより汎用的に使える• メンバーでなくても使える
• Optional の方がより汎用的な言語仕様• 多くの言語の Maybe モナドに近い
• 「 null 伝搬演算子」の方がコンパクトに記述できる
C#6.0 とのアプローチの違い
結果としてC#6.0 と同じような問題が解けているように見えるが…
C# の方がより具体的な問題を
実用的に解いている
Java の方が一般的・汎用的
C#6.0•具体的な問題を実用的に解いている
Java8•一般的な問題を汎用的に解いている
C#6.0 の進化は現実の C# プログラマーの
「こう書きたい」を叶えようと
している
Let’s enjoy C#!