5. 例えばrange
• これまで
• C# 8.0
var y = x.Slice(a, b);
aからbまでの意味だっけ?
b自体は含む?その1個手前まで?
aからb個の意味だっけ?
var y = x[a..b];
文法的に意味が確定
• aからbまでの意味
• b自体は含まない
var y = x.Slice(a); aから後ろの意味だっけ?
先頭からa個の意味だっけ?
var y = x[a..]; • aから後ろ
var y = x[..a]; • 先頭からa個
9. 例えばswitch
• パターン マッチングの拡充
• そもそもC# 7.3の頃まではこんな書き方になってた
static int CompareTo(int? x, int? y)
{
if (x is int x1)
if (y is int y1) return x1.CompareTo(y1);
else return 1;
else
if (y is int y1) return -1;
else return 0;
}
10. 参考
• Preview版の頃から割と安定していた機能は4月の登壇を参照
Visual Studio 2019 Launch
(https://connpass.com/event/122145/)
C# 8.0 Preview in Visual Studio 2019 (16.0)
(https://www.slideshare.net/ufcpp/c-80-preview-in-visual-studio-2019-160)
46. AllowNull
• ?が付いていなくてもnullを受け付ける
public class TextWriter
{
public virtual string NewLine
{
get;
[AllowNull] set;
}
}
例: TextWrite.NewLine (System.IO)
setだけnullable
(nullを渡すとEnvironment.NewLineに置き換える仕様)
var t = new StreamWriter(path);
Console.WriteLine(t.NewLine.Length);
t.NewLine = null;
getはnot null
setはnullを
渡しても平気
47. DisallowNull
• ?が付いていてもnullを受け付けない
public interface IEqualityComparer<in T>
{
bool Equals([AllowNull] T x, [AllowNull] T y);
int GetHashCode([DisallowNull] T obj);
}
例: IEqualityComparer (System.Collections.Generic)
同じ型引数に対して
メソッドごとにnull許容性が違う
var c = EqualityComparer<string>.Default;
c.Equals("", null);
var h = c.GetHashCode(null); これはOK
こっちは警告
48. MaybeNull
• ?が付いていなくてもnullを返すことがある
public class Array
{
[return: MaybeNull]
public static T Find<T>(T[] array, Predicate<T> match);
}
例: Array.Find (System)
条件を満たす要素がなかったらdefaultを返す
var array = new[] { "a", "bc" };
var s = Array.Find<string>(array, s => s.Length == 3);
Console.WriteLine(s.Length);
型はstring (not null)でもnullがあり得る(警告)
49. NotNull
• ?が付いていてもnullを返さない
public class Array
{
public static void Resize<T>([NotNull] ref T[]? array, int newSize);
}
例: Array.Resize (System)
nullを受け付けるけど、
メソッドを抜けるまでに非nullで上書き
int[]? array = null;
Array.Resize(ref array, 1);
Console.WriteLine(array.Length);
nullを渡しても平気
でもnullは返ってこない
50. MaybeNullWhen
• 戻り値の真偽次第ではmaybe null
例: Dictionary.TryGetValue (System.Collections.Generic)
public class Dictionary<TKey, TValue>
{
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value);
}
戻り値がfalseの時だけvalueがmaybe null
if (map.TryGetValue(1, out var s)) Console.WriteLine(s.Length);
else Console.WriteLine(s.Length);
戻り値がtrueなのでnot null
戻り値がfalseなのでmaybe null (警告)
51. NotNullWhen
• 戻り値の真偽次第ではnot null
例: string.IsNullOrEmpty
public class String
{
public bool IsNullOrEmpty([NotNullWhen(false)] string value);
}
戻り値がfalseの時だけvalueがnot null保証あり
if (string.IsNullOrEmpty(s)) Console.WriteLine(s.Length);
else Console.WriteLine(s.Length);
戻り値がtrueなのでmaybe null (警告)
戻り値がfalseなのでnot null
52. NotNullIfNotNull
• 引数がnot nullの時だけ戻り値がnot null
例: File.GetFileName (System.IO)
※ 命名規約的に
• when : 戻り値に応じて引数を判定
• if : 引数に応じて戻り値を判定
public static class Path
{
[return: NotNullIfNotNull("path")]
public static string GetFileName(string path);
}
path引数のnull許容性がそのまま戻り値に伝搬
var l1 = Path.GetFileName("sample.txt").Length;
var l2 = Path.GetFileName(null).Length;
引数がnullなので戻り値もnull (警告)
53. DoesNotReturn
• メソッドを呼んだが最後、戻ってこない
例: Environment.FailFast (System)
public static class Environment
{
[DoesNotReturn]
public static void FailFast(string message);
}
プログラムを即停止。絶対戻ってこない
string? s = null;
if (flag) s = "abc";
else Environment.FailFast("fail");
Console.WriteLine(s.Length);
分岐の片方は値の代入あり
もう片方は戻ってこない
結果的にnot null保証あり
54. DoesNotReturnIf
• 特定の引数でメソッドを呼んだら戻ってこない
例: Debug.Assert (System.Diagnostics)
public static class Debug
{
public static void Assert([DoesNotReturnIf(false)] bool condition)
}
この引数にfalse渡して呼ぶと即停止
Debug.Assert(s != null);
Console.WriteLine(s.Length);
falseだと即停止
s != null が成立しているはず
結果的にsはnot null