SlideShare une entreprise Scribd logo
1  sur  56
C# 8.0
null許容参照型
岩永 信之
今日の話
• C# 8.0と堅牢性
• そもそもnullはなぜあって、何が問題か
• null許容参照型
C# 8.0
本題の前にさらっと
Robustness (堅牢性)
• C# 8.0の大きなテーマは堅牢性の向上
• コンパイラーによるチェックの強化で人的ミスを減らす
• 今日の本題(null許容参照型)もその一環
例えば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個
例えばswitch
• パターン マッチングの拡充
• 網羅性チェックも賢くなってる
static int CompareTo(int? x, int? y)
=> (x, y) switch
{
(null, null) => 0,
(null, { }) => -1,
({ }, null) => 1,
};
パターン足りてないよ?(警告)
(足りてないものが来た
ときには実行時例外)
例えばswitch
• パターン マッチングの拡充
• 網羅性チェックも賢くなってる
static int CompareTo(int? x, int? y)
=> (x, y) switch
{
(null, null) => 0,
(null, null) => -1,
({ }, null) => 1,
({ } x1, { } y1) => x1.CompareTo(y1),
};
パターン被ってるよ?(エラー)
例えばswitch
• パターン マッチングの拡充
• 網羅性チェックも賢くなってる
static int CompareTo(int? x, int? y)
=> (x, y) switch
{
(null, null) => 0,
(null, { }) => -1,
({ }, null) => 1,
({ } x1, {} y1) => x1.CompareTo(y1),
};
正しくはこう
例えば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;
}
参考
• 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)
null
nullとは
nullで何が問題になるか
nullとは
• null = 無効なことが絶対に保証できるポインター
• 未定義動作よりは即死の方がマシ
string s = "";
Unsafe.As<string, IntPtr>(ref s) = (IntPtr)123456789;
やろうと思えばC#でも不正な場所を参照できる
よくわからない適当な値
アクセス違反 未定義動作になる
• OSが怒ってくれればまだマシな方
• 下手するとセキュリティホール
• ダメなものを読み書きできる
nullとは
• null = 無効なことが絶対に保証できるポインター
• 未定義動作よりは即死の方がマシ
string s = "";
Unsafe.As<string, IntPtr>(ref s) = (IntPtr)0;
アドレス0は無効とする
よくわからない値よりは
よく知った無効な値が好ましい
• 無効な場所を参照したことを確実に検知
• セキュリティホールよりはマシ
ぬるぽ
(おまけ)読めちゃいけない場所を読む
• アクセス違反を即座には起こさない例
• ただし、GCが起きるとぶっ壊れる
• (ExecutionEngineException)
string s = null;
byte* p = stackalloc byte[20];
*(int*)(p + 8) = 3;
*(long*)(p + 12) = 0x0043_0042_0041;
Unsafe.As<string, IntPtr>(ref s) = (IntPtr)(void*)p;
Console.WriteLine(s[0]); // A (U+0041)
Console.WriteLine(s[1]); // B (U+0042)
Console.WriteLine(s[2]); // C (U+0043)
適当にstringと同じ構造の
データを用意
そこを参照
無効だとわかるならそれでいいのか
• 例外発生場所と真の原因が遠い
void A() => B(null);
void B(string s) => C(s);
void C(string s) => D(s);
void D(string s) => E(s);
void E(string s) => F(s);
void F(string s) => Console.WriteLine(s.Length);
真犯人
事件現場
おまえのせいか?
おまえ?
やっぱ、おまえ?
いや、おまえ?
すまん、俺だわ
過剰nullチェック
• 過剰防衛になりがち
void A(string s)
{
if (s != null) B(s);
}
void B(string s)
{
if(s != null) Console.WriteLine(s.Length);
}
nullが来てまずいかどうか、
外から見てわからない
だから自衛のためにnullチェック
でも実は中でもnullチェックしてた
過剰nullチェック対策
• 「中身」は変わる可能性がある
void B(string s)
{
if(s != null)
Console.WriteLine(s.Length);
}
シグネチャ (signature)
• 外から見える部分
• ここは変えた時点で即「破壊的変更」
中身 (body)
• 外からは見えない
• ここは変えても使ってる側にコンパイル
エラーが出ない
過剰nullチェック対策
• 「中身」は変わる可能性がある
• シグネチャだけ見て「nullかどうか」がわからないとダメ
void B(string s)
{
if(s != null)
Console.WriteLine(s.Length);
}
見えない
「この s はnullを受け付けます/受け付けません」
という注釈(annotation)が欲しい
null許容性
• メソッドシグネチャにnull許容性の注釈が必要
string A(string s);
string? A(string s);
string A(string? s);
string? A(string? s);
nullを
受け付けません
nullを
受け付けます
nullを
返しません
nullを
返します
null許容参照型
概要と有効化方法
null許容型
• C# 2.0からnull許容値型がある
• 本来は「無効なポインター」だったものが単に「無効な値」に
• C# 8.0からnull許容参照型ができる
• これまでと「string」の意味が変わる
• 既存コードを壊さないためにオプションで切り替え方式(opt-in)
void A(int x);
void B(int? x);
nullを受け付けない
nullを受け付ける
void A(string x);
void B(string? x);
nullを受け付けない
nullを受け付ける
シグネチャだけでわかる
有効化(C#ソースコード単位)
• #nullable ディレクティブ
• #if や #warning と一緒で、そこから下の行に影響
#nullable enable
int.Parse(null);
#nullable disable
int.Parse(null);
stringにnullを渡すと警告
(新挙動)
警告なし
(従来挙動)
有効化(プロジェクト単位)
• csprojに以下の行を追加
• 将来的に、デフォルトでこの行が入る可能性あり
• 既存プロジェクトをうかつに変えると怖いけど、新規プロジェクトなら平気
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
not null, maybe null, oblivious
• 型には3つの状態ができる
#nullable enable
string x = "";
string? x = null;
#nullable disable
string x = null;
not null: 絶対nullではない
maybe null: nullがあり得る
oblivious※: 無効になってるのでnull
かどうか知りようがない
(違反があっても一切警告が出ない)
※ oblivious = 忘れてる、気付かない
注釈のみ、警告のみ
• #nullable enable/disableにはさらに以下のオプションあり
• annotations : 注釈のみつける
• warnings : 警告だけは出す
(移行期、ライブラリ作者のために機能分割)
void M(string s)
{
int.Parse(s);
string local = null;
int.Parse(local);
}
例えばこんなコードがあったとして
ちなみに、int.Parse
の引数はnot null
注釈のみ、警告のみ(両方disable)
• #nullable enable/disableのオプション
• #nullable disable とだけ書くと両方とも無効化
#nullable disable
void M(string s)
{
int.Parse(s);
string local = null;
int.Parse(local);
}
disable (既存挙動のまま)の時
oblivious
obliviousなので警告対象外
oblivious
nullだとわかってても警告対象外
注釈のみ、警告のみ(両方enable)
• #nullable enable/disableのオプション
• #nullable enable とだけ書くと両方とも有効化
#nullable enable
void M(string s)
{
int.Parse(s);
string local = null;
int.Parse(local);
}
enable の時
not null
not nullをnot nullに渡しているのでOK
nullをnot nullに渡しているので警告
たどっていくとnullなことが
わかっているのでここでも警告
新挙動に完全に対応しました
注釈のみ、警告のみ
• #nullable enable/disableのオプション
• #nullable enable annotations で注釈だけ有効化
• #nullable disable annotations で注釈だけ無効化
#nullable enable annotations
void M(string s)
{
int.Parse(s);
string local = null;
int.Parse(local);
}
enable annotations (注釈だけ付ける)の時
not null シグネチャ部分には影響する
中身には影響しない
一切警告が出ない
差し当たって対応したふり
中身の保証ないけど
注釈のみ、警告のみ
• #nullable enable/disableのオプション
• #nullable enable warnings で警告だけ有効化
• #nullable disable warnings で警告だけ無効化
#nullable enable warnings
void M(string s)
{
int.Parse(s);
string local = null;
int.Parse(local);
}
enable warnings (警告だけ出す)の時
oblivious シグネチャ部分には影響しない
中身には影響する
obliviousなので警告対象外
nullをoblivious渡しても平気
たどっていくとnullなことが
わかっているのでここで警告
対応しきった自信はない
中身の保証はしてるんだけど
フロー解析
nullチェックの掛かり方
フロー解析
• ソースコードの処理の流れ(フロー)を追ってエラーを見つける
• C# 1.0時代から、変数の代入漏れのフロー解析あり
string s;
// 初期化しないまま s を使ったのでエラー。
Console.WriteLine(s.Length);
フロー解析
• ソースコードの処理の流れ(フロー)を追ってエラーを見つける
• C# 1.0時代から、変数の代入漏れのフロー解析あり
• ちゃんと分岐を見る
string s;
if (true) s = "abc";
Console.WriteLine(s.Length);
string s;
if (false) s = "abc";
Console.WriteLine(s.Length);
static void M2(bool flag)
{
string s;
if (flag) s = "abc";
else s = "def";
Console.WriteLine(s.Length);
}
static void M(bool flag)
{
string s;
if (flag) s = "abc";
Console.WriteLine(s.Length);
}
絶対通らない
else時の
初期化がない
null許容参照型もフロー解析で実装
• ソースコードの流れを追ってnullかどうかを判定
• 出所がnull許容かどうか
• nullチェックをしたかどうか
string? s;
s = "abc";
Console.WriteLine(s.Length);
s = null;
Console.WriteLine(s.Length);
非nullな値を代入していれば
警告が出なくなる
nullを代入すれば
警告が出るようになる
null許容で宣言していても
null許容参照型もフロー解析で実装
• ソースコードの流れを追ってnullかどうかを判定
• 出所がnull許容かどうか
• nullチェックをしたかどうか
var p = typeof(string).GetProperty("Length");
Console.WriteLine(p.PropertyType);
戻り値がnull許容
なので警告が出る
null許容参照型もフロー解析で実装
• ソースコードの流れを追ってnullかどうかを判定
• 出所がnull許容かどうか
• nullチェックをしたかどうか
var p = typeof(string).GetProperty("Length");
if (p is null) return;
Console.WriteLine(p.PropertyType);
nullチェックを挟めば
警告が消える
null許容参照型もフロー解析で実装
• ソースコードの流れを追ってnullかどうかを判定
• == でnull許容性が伝搬したり
void Equality(string x, string? y)
{
if (x == y)
{
Console.WriteLine(y.Length);
}
else
{
Console.WriteLine(y.Length);
}
}
非nullなものと一致
警告なし
警告あり
注意: 値型と参照型
• null許容値型は明確に別の型
• Nullable<T>型(System名前空間)
• オーバーロードにも使える
• null許容参照型は単なる注釈
• 型情報的には属性だけの差
• オーバーロードできない
void M(int? x) { }
void M(Nullable<int> x) { }
void M(string? x) { }
void M([Nullable(2)] string x) { }
void M(int x) { }
void M(int? x) { }
void M(string x) { }
void M(string? x) { }
⭕ ❌
注意: 特にジェネリックなとき面倒
• 型引数に対するT?
• 型制約なしだとコンパイル エラーに
• .NETの型システムのレベルで改修入れない限り無理
void M<T>(T? x) { }
Nullable<T> x [Nullable(2)] T x
値型? 参照型?
struct制約
• struct制約 → T?はnull許容値型(C# 2.0の頃からの挙動)
static void M<T>(T? x)
where T : struct { }
static void Main()
{
M<int>(0);
M<int?>(0);
M<string>("");
M<string?>(null);
}
Nullable<T>の意味
非nullな値型しか受け付けない
(他はエラーに)
class制約
• class制約 → not nullな参照型の意味に。T?と書ける
static void M<T>(T? x)
where T : class { }
static void Main()
{
M<int>(0);
M<int?>(0);
M<string>("");
M<string?>(null);
}
[Nullable(2)] Tの意味
値型は受け付けない(エラー)
null許容参照型は受け付けない(警告)
class?制約
• class?制約 → nullableの意味に。T?とは書けない
static void M<T>(T x)
where T : class? { }
static void Main()
{
M<string>("");
M<string?>(null);
}
ちなみに、コンパイル結果は
void M<[Nullable(2)] T>(T x)
OK
static void M<T>(T? x)
where T : class? { }
エラー
notnull制約
• notnull制約 → not nullの意味に。T?とは書けない
static void M<T>(T x)
where T : notnull { }
static void Main()
{
M<int>(0);
M<int?>(0);
M<string>("");
M<string?>(null);
}
ちなみに、コンパイル結果は
void M<[Nullable(1)] T>(T x)
?が付いた型を渡すと警告
static void M<T>(T? x)
where T : notnull { }
エラー
注意: 既定値にも甘い
• コンストラクターがないとnullチェックができない
• 既定値が絡むとnullチェックが漏れてる
struct S { public string Name; }
static int M(S s) => s.Name.Length;
static void Main() => M(default);
例: 構造体のdefault(T)
nullが来るけど無警告
var array = new string[1];
Console.WriteLine(array[0].Length);
例: 配列
nullが来るけど無警告
後置き ! 演算子
• フロー解析には限界あり
• 循環があるときは解析できない
• 理屈的に可能としても、コスト的に無理なことも
• 徐々に解析できる範囲が広がる可能性はあり
• 過剰に警告が出ることが多いので無視する手段が必要
• !を付けると警告抑止
#nullable enable
string NotNull = null!;
not nullなフィールドにnullを入れられる
「後でちゃんとした値入れるから今は見逃して」
var l = s!.Length; // (s!).Length の意味
var b = s !is null; // (s!) is null の意味
※ ちょっと誤解されそうな書き方もできるので注意
関連属性
• T?記法だけでは対応できないものがある
• ジェネリックな型
• get/setでnull許容性が違うプロパティ
• ref引数で「nullを受け付けるけど返さない」
• TryParseみたいな条件付き非null
• 属性で対応
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を
渡しても平気
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
こっちは警告
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があり得る(警告)
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は返ってこない
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 (警告)
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
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 (警告)
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保証あり
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
特殊対応
• いくつかのメソッドには特別扱いあり
• 属性を使って汎用化するほどの要求がないので特殊対応
• Equals系(object.Equals, IEquatable, IEqualityComparerなど)
void Equality(string x, string? y)
{
if (EqualityComparer<string>.Default.Equals(x, y))
{
Console.WriteLine(y.Length);
}
else
{
Console.WriteLine(y.Length);
}
}
x == y の時と同じ
ルールでフロー解析
警告なし
警告あり
まとめ
• C# 8.0の大きなテーマは堅牢性の向上
• その中でも一番大きいのがnull許容参照型
• 参照型でもTとだけ書くと非null、T?でnull許容
• ?だけでは表現できないもの向けの属性あり
• 破壊的変更を避けるためにopt-in
• #nullableディレクティブ / Nullableコンパイル オプション
• フロー解析で実装
• null許容値型と差があるので注意
• 解析が難しい場面あり
• ジェネリクス、既定値など
• 回避策として ! 演算子(警告握り潰し)

Contenu connexe

Tendances

オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
Moriharu Ohzu
 

Tendances (20)

テスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるなテスト文字列に「うんこ」と入れるな
テスト文字列に「うんこ」と入れるな
 
REST API のコツ
REST API のコツREST API のコツ
REST API のコツ
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
Where狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーWhere狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキー
 
Yahoo!ニュースにおけるBFFパフォーマンスチューニング事例
Yahoo!ニュースにおけるBFFパフォーマンスチューニング事例Yahoo!ニュースにおけるBFFパフォーマンスチューニング事例
Yahoo!ニュースにおけるBFFパフォーマンスチューニング事例
 
できる!並列・並行プログラミング
できる!並列・並行プログラミングできる!並列・並行プログラミング
できる!並列・並行プログラミング
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方
 
ワタシはSingletonがキライだ
ワタシはSingletonがキライだワタシはSingletonがキライだ
ワタシはSingletonがキライだ
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
 
ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計
 
SPAのルーティングの話
SPAのルーティングの話SPAのルーティングの話
SPAのルーティングの話
 
Tackling Complexity
Tackling ComplexityTackling Complexity
Tackling Complexity
 
C# 8.0 非同期ストリーム
C# 8.0 非同期ストリームC# 8.0 非同期ストリーム
C# 8.0 非同期ストリーム
 
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
 
GraphQLのsubscriptionで出来ること
GraphQLのsubscriptionで出来ることGraphQLのsubscriptionで出来ること
GraphQLのsubscriptionで出来ること
 
こわくない Git
こわくない Gitこわくない Git
こわくない Git
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
 

Similaire à C# 8.0 null許容参照型

Similaire à C# 8.0 null許容参照型 (8)

C# 9.0 / .NET 5.0
C# 9.0 / .NET 5.0C# 9.0 / .NET 5.0
C# 9.0 / .NET 5.0
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
 
C# linq入門 意図編
C# linq入門 意図編C# linq入門 意図編
C# linq入門 意図編
 
C++0x 言語の未来を語る
C++0x 言語の未来を語るC++0x 言語の未来を語る
C++0x 言語の未来を語る
 
Introduction to programming
Introduction to programmingIntroduction to programming
Introduction to programming
 
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#
 
C++ tips4 cv修飾編
C++ tips4 cv修飾編C++ tips4 cv修飾編
C++ tips4 cv修飾編
 
ソフトウェア工学2023 12 コードフォーマット
ソフトウェア工学2023 12 コードフォーマットソフトウェア工学2023 12 コードフォーマット
ソフトウェア工学2023 12 コードフォーマット
 

Plus de 信之 岩永

Code Contracts in .NET 4
Code Contracts in .NET 4Code Contracts in .NET 4
Code Contracts in .NET 4
信之 岩永
 

Plus de 信之 岩永 (20)

YouTube ライブ配信するようになった話
YouTube ライブ配信するようになった話YouTube ライブ配信するようになった話
YouTube ライブ配信するようになった話
 
C# コンパイラーの書き換え作業の話
C# コンパイラーの書き換え作業の話C# コンパイラーの書き換え作業の話
C# コンパイラーの書き換え作業の話
 
Unicode文字列処理
Unicode文字列処理Unicode文字列処理
Unicode文字列処理
 
C# 8.0 Preview in Visual Studio 2019 (16.0)
C# 8.0 Preview in Visual Studio 2019 (16.0)C# 8.0 Preview in Visual Studio 2019 (16.0)
C# 8.0 Preview in Visual Studio 2019 (16.0)
 
async/await のしくみ
async/await のしくみasync/await のしくみ
async/await のしくみ
 
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1
 
C#言語機能の作り方
C#言語機能の作り方C#言語機能の作り方
C#言語機能の作り方
 
Unityで使える C# 6.0~と .NET 4.6
Unityで使える C# 6.0~と .NET 4.6Unityで使える C# 6.0~と .NET 4.6
Unityで使える C# 6.0~と .NET 4.6
 
それっぽく、適当に
それっぽく、適当にそれっぽく、適当に
それっぽく、適当に
 
Modern .NET
Modern .NETModern .NET
Modern .NET
 
.NET Compiler Platform
.NET Compiler Platform.NET Compiler Platform
.NET Compiler Platform
 
Deep Dive C# 6.0
Deep Dive C# 6.0Deep Dive C# 6.0
Deep Dive C# 6.0
 
Orange Cube 自社フレームワーク 2015/3
Orange Cube 自社フレームワーク 2015/3Orange Cube 自社フレームワーク 2015/3
Orange Cube 自社フレームワーク 2015/3
 
Code Contracts in .NET 4
Code Contracts in .NET 4Code Contracts in .NET 4
Code Contracts in .NET 4
 
今から始める、Windows 10&新.NETへの移行戦略
今から始める、Windows 10&新.NETへの移行戦略今から始める、Windows 10&新.NETへの移行戦略
今から始める、Windows 10&新.NETへの移行戦略
 
今から始める、Windows 10&新.NETへの移行戦略
今から始める、Windows 10&新.NETへの移行戦略今から始める、Windows 10&新.NETへの移行戦略
今から始める、Windows 10&新.NETへの移行戦略
 
C# design note sep 2014
C# design note sep 2014C# design note sep 2014
C# design note sep 2014
 
.NET vNext
.NET vNext.NET vNext
.NET vNext
 
C#/.NETがやっていること 第二版
C#/.NETがやっていること 第二版C#/.NETがやっていること 第二版
C#/.NETがやっていること 第二版
 
Coding Interview
Coding InterviewCoding Interview
Coding Interview
 

C# 8.0 null許容参照型