16. 自動プロパティ初期化子
• 自動プロパティに対して初期化子が書けるように
• 明示的なフィールド定義が不要に
class Root
{
private List<string> _items = new List<string>();
public IList<string> Items { get { return _items; } }
}
class Root
{
public IList<string> Items { get; private set; } = new List<string>();
}
17. getter-onlyな自動プロパティ
• コンストラクター内でだけ初期化できる自動プロパティ
• { get; } だけ書く
class Immutable
{
private readonly int _x;
public int X { get { return _x; } }
public Immutable(int x) { _x = x; }
}
class Immutable
{
public int X { get; }
public Immutable(int x) { X = x; }
}
18. 没案: プライマリ コンストラクター
• 当初予定では、もう1つ文法が提案されてた
• C# 7.0で、より高度な新機能に統合予定
• プライマリ コンストラクター(没) → レコード型(7.0)
class Immutable(int x)
{
public int X { get; } = x;
}
class Immutable
{
public int X { get; }
public Immutable(int x) { X = x; }
}
プライマリ コンストラクター(没)
未
23. using static
• 静的メソッドを、メソッド名だけで呼べるように
• using static構文を使う
using System;
public class Program
{
static void Main()
{
Console.WriteLine("hello");
}
}
using static System.Console;
public class Program
{
static void Main()
{
WriteLine("hello");
}
}
System.Console.WriteLine が呼ばれる
24. using staticの用途(1)
• クラスにあまり意味がないもの
• グローバル関数の代わり
• Mathとかが好例
using static System.Math;
class MathSample
{
double F(int x) => x * Log(x);
double G(int x) => Sin(x) * Exp(x);
}
数学関数ばっかり使うような文脈で、
1個1個 Math. を付けたくない
25. using staticの用途(2)
• ファクトリ メソッド
• 諸事情あってコンストラクターを公開せず、メソッド越しに作るもの
• Expressionとかが好例
using System.Linq.Expressions;
using static System.Linq.Expressions.Expression;
class ExpressionSample
{
static ParameterExpression x = Parameter(typeof(int));
static ParameterExpression y = Parameter(typeof(int));
static Expression ex = Lambda(Add(x, y), x, y);
}
Expressionクラスの静的メソッドで
インスタンス生成
27. 静的プロパティ/非静的クラス
• 静的プロパティ可
• 静的クラスである必要ない
using static System.DateTime;
using static System.Console;
public class Program
{
public static void Main()
{
WriteLine(Now);
}
}
普通の(static が付かない)クラス
(こっちは静的クラス)
静的プロパティ
29. staticが付く理由
• もし、staticを付けないと
• 当初提案では付けなくてもよかった
• 結構極悪なコードを書けてやばかったから修正
using System.Linq;
namespace System
{
public static class Linq
{
public static string nameof(Action x) => "";
}
}
既存の名前空間と同名のクラス
元とは別の定義を紛れ込ませられる
没
30. null条件演算子(null conditional operator)
• ?. で nullチェック + メンバー アクセス
• 左辺が null だったら戻り値に null 伝搬
• ?? と組み合わせるのも有効
string name;
if (unit == null) name = "空欄";
else name = unit.Master.Name;
var name = unit?.Master.Name ?? "空欄";
var name = unit == null ?
"空欄" :
unit.Master.Name;
あるいは
31. インデクサー/多段チェック
• ?[] でインデクサーに対しても null チェック可能
• 1つの式で多段チェック可能
var m = team.Units?[0]?.Master;
var unit = team.Units != null ?
team.Units[0] :
null;
var m = unit != null ?
unit.Master :
null;
38. IFormattable
• IFormatProviderを指定したい場合
• (カルチャー指定などをしたい場合)
• stringじゃなくてIFormattableで受ける
• .NET 4.6/.NET Core 5を必要とする唯一の機能
• FormattableStringは新しく追加された型
• (他は、await除けば.NET 2.0で動く)
IFormattable f = $"{x:c}, {x:n}";
var s = f.ToString(null, new CultureInfo("en-us"));
FormattableString型の
インスタンスが作られる
カルチャー指定して文字列化
39. nameof式(nameof expression)
• 識別子(変数名、メンバー名、クラス名…)を文字列リテラル化
if (x < 0)
throw new ArgumentException("x must be positive");
if (x < 0)
throw new ArgumentException(nameof(x) + " must be positive");
リファクタリングの対象にならない
リファクタリングの対象になる
• 「リネーム」できる
• 「定義に移動」できる
• 「参照の検索」できる
40. nameof式(nameof expression)
• 結構複雑な式も書ける
var now = DateTime.Now;
var x1 = nameof(now.AddHours);
var x2 = nameof(IList<int>.Count);
var x3 = nameof(System.Text.RegularExpressions.Regex);
AddHours
Count
Regex
41. 補足: CallerMemberName
• PropertyChanged用途だと、こんな方法も
• ただし、これでは不十分場合あり
private int _x;
public int X
{
get { return _x; }
set { _x = value; OnPropertyChanged(); }
}
void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
自動的に"X"の名前が渡る
42. 補足: CallerMemberNameでは不十分
• パフォーマンス考えるとよりよい書き方があって
public int X
{
get { return _x; }
set { _x = value; PropertyChanged?.Invoke(this, XProperty); }
}
private static readonly PropertyChangedEventArgs XProperty
= new PropertyChangedEventArgs(nameof(X));
同じインスタンスを使いまわす
方がメモリ効率がいい
この場合、CallerMemberName
では役に立たない
43. 補足: CallerMemberNameでは不十分
• 他のプロパティに依存したプロパティ
public int X
{
get { return _x; }
set { _x = value; OnPropertyChanged(); OnPropertyChanged(nameof(Sum)); }
}
public int Y
{
get { return _y; }
set { _y = value; OnPropertyChanged(); OnPropertyChanged(nameof(Sum)); }
}
public int Sum => X + Y;
X, Y の一方でも変化したら
Sumの値も変化する
この場合、CallerMemberName
では役に立たない
44. インデックス初期化子
• オブジェクト初期化子内にインデクサーを書ける
• 利点
• オブジェクト初期化子で、プロパティと混ぜれる
• 式になる
• => で使える、フィールド初期化子で使える、式ツリー化できる
var d = new Dictionary<string, int>
{
["X"] = 1,
["Y"] = 2,
};
46. light weight dynamic
• プロパティ アクセスと辞書アクセスを近づける発想
var p = new Point();
p.X = 1;
p.Y = 2;
var d = new Dictionary();
d["X"] = 1;
d["Y"] = 2;
var p = new Point
{
X = 1,
Y = 2,
};
var d = new Dictionary
{
["X"] = 1,
["Y"] = 2,
};
var d = new Dictionary();
d.$X = 1;
d.$Y = 2;
var d = new Dictionary
{
$X = 1,
$Y = 2,
};
没
没
一瞬、こういう文法が提案されてた
(キモいって言うやつ多すぎるからやめた)
47. Working with data
• C# 7.0の大きなテーマの1つ
• light weight dynamicはそのはしり
• 7.0にご期待ください
• レコード型、タプル型
「データ」が主役
var d = new Dictionary
{
["X"] = 1,
["Y"] = 2,
};
低コスト、低リスクなこいつだけが6.0に残った
55. 拡張メソッドでコレクション初期化子
• コレクション初期化子の結果として呼ばれるAddメソッドが
拡張メソッドでもOKに
var points = new List<Point>
{
new Point(3, 4),
};
var points = new List<Point>();
points.Add(new Point(3, 4));
var points = new List<Point>
{
{ 3, 4 },
};
var points = new List<Point>();
points.Add(3, 4);
static class PointExtensions
{
public static void Add(
this IList<Point> list, int x, int y)
=> list.Add(new Point(x, y));
}
67. 追悼: 構造体の引数なしコンストラク
ター
• 構造体にも引数なしのコンストラクターを定義できるようにす
るはずだった
• .NETのランタイム レベルでバグがあることが発覚して断念
• Activator.CreateInstance<T>() が new T() をnullに置き換える
struct MyInt
{
public readonly int Value;
public MyInt() { Value = -1; }
public MyInt(int value) { Value = value; }
}
没
68. 追悼: プライマリ コンストラクター
• 型定義の型名の直後にコンストラクターを1個書けた
• 7.0でレコード型に吸収予定
class Immutable(int x)
{
public int X { get; } = x;
}
class Immutable(int x) { } 未
未
69. 追悼: 変数宣言式(declaration expressions)
• 式の途中で変数宣言できた
• 7.0でパターン マッチングと合わせて作り直す予定
while ((var line = Console.ReadLine()) != null)
if (int.TryParse(line, out var x))
(var y = Math.Sin(x)) * y;
if (x is string s) { … }
else if (x is int n) { … }
未
未