22. unsafeでも制限付き
• class (参照型)はアドレス取れない
• 仮想メソッド テーブル(vtable)とか入ってるし
• 親クラス側のレイアウト変更の影響受けるし
class Class
var c
{
fixed
public int x;
fixed
public int y;
fixed
}
ピン止め必須
•
•
= new Class();
(void* p = &c) { }
// error
(void* p = &c.x) { } // OK
(void* p = &c.y) { } // OK
値型のメンバーのアドレスは取れる
オブジェクト自体のアドレスは取れ
ない
23. unsafeでも制限付き
• struct (値型)はアドレス取れる
• ただし、メンバーが全部値型の時のみ
• ↑「unmanaged型」と呼ぶ
struct UnmanagedStruct
{
public int x;
public int y;
}
メンバーが
全部値型
var u
void*
void*
void*
= new UnmanagedStruct();
p1 = &u;
// OK
p2 = &u.x; // OK
p3 = &u.y; // OK
無制限にアドレス取れる
24. unsafeでも制限付き
• struct (値型)であっても制限付き
• メンバーに1つでも参照型を含むとダメ
• ↑「managed型」と呼ぶ
struct ManagedStruct
{
public int x;
public string y;
}
メンバーに
参照型が1つ
var u
void*
void*
void*
= new ManagedStruct();
p1 = &u;
// error
p2 = &u.x; // OK
p3 = &u.y; // error
値型のメンバーのところ
だけはアドレス取れる
43. 差分ダウンロード
※ Windowsストア アプリはこの仕組み持ってるらしい
アプリAパッケージ version 1
アプリA
version 1
アプリAパッケージ version 2
ライブラリX
version 1
アプリA
version 1
ライブラリY
version 1
ライブラリX
version 2
ライブラリY
version 1
差分
ライブラリX
version 2
バージョンアップ時
ダウンロード
アプリA ver.1
インストール機
55. 数値でのフィールド参照
• C#で擬似的に書くと
static int GetVolume(Point p)
{
return p.X * p.Y * p.Z;
}
var pp = (byte*)&p;
var x = *((int*)pp);
var y = *((int*)(pp + 4));
var z = *((int*)(pp + 8));
return x * y * z;
4とか8とかの数値に
※これ、一応C#として有効なコード(unsafe)
72. 標準ライブラリ
• まして今、Xamarin (Mono)
• Xamarin.iOS、Xamarin.Android
Windows
タブレット/Phone
Windows
デスクトップ
Windows
サーバー
iOS
Android
この共通部分だけを
「標準」にすべき?
Linux
サーバー
89. とはいえ、いろいろ窮屈
• genericsでは、インターフェイス制約かけない
とメソッドすら呼べない
static Type Max<Type>(Type a, Type b)
{
return a.CompareTo(b) > 0 ? a : b;
}
コンパイル エラー
そんなメソッド知らない
正しくは
static Type Max<Type>(Type a, Type b)
where Type : IComparable
インターフェイス制約
{
return a.CompareTo(b) > 0 ? a : b;
}
IComparable.CompareTo
95. 例
• substringの列挙
実装側
static IEnumerable<string> GetSubstrings(string s)
{
for (var len = s.Length; len >= 1; len--)
for (var i = 0; i <= s.Length - len; i++)
yield return s.Substring(i, len);
}
イテレーター ブロック†
(= yield returnを持つ関数ブロック)
使う側
foreach (var x in GetSubstrings("abcd"))
Console.WriteLine(x);
96. 内部実装(全体像)
• クラス生成
class SubstringEnumerable : IEnumerator<string>, IEnumerable<string>
{
readonly string _s;
int _len;
int _i;
int _state = 0;
public SubstringEnumerable(string s) { _s = s; }
public string Current { get; private set; }
public bool MoveNext()
{
if (_state == 1) goto STATE1;
if (_state == -1) goto END;
_state = 1;
_len = _s.Length;
LOOP1BEGIN: ;
if (!(_len >= 1)) goto LOOP1END;
_i = 0;
LOOP2BEGIN: ;
if (!(_i <= _s.Length - _len)) goto LOOP2END;
_state = 1;
Current = _s.Substring(_i, _len);
return true;
STATE1: ;
_i++;
goto LOOP2BEGIN;
LOOP2END: ;
_len--;
goto LOOP1BEGIN;
LOOP1END: ;
_state = -1;
END: ;
return false;
}
static IEnumerable<string> GetSubstrings(string s)
{
for (var len = s.Length; len >= 1; len--)
for (var i = 0; i <= s.Length - len; i++)
yield return s.Substring(i, len);
}
public void Reset() { throw new NotImplementedException(); }
public void Dispose() { }
object IEnumerator.Current { get { return Current; } }
public IEnumerator<string> GetEnumerator()
{
if(_state == 0) return this;
else return new SubstringEnumerable(_s).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
97. 内部実装(ローカル変数)
• ローカル変数 → フィールド
static IEnumerable<string> GetSubstrings(string s)
{
for (var len = s.Length; len >= 1; len--)
for (var i = 0; i <= s.Length - len; i++)
yield return s.Substring(i, len);
}
class SubstringEnumerable : IEnumera
{
readonly string _s;
int _len;
int _i;
int _state = 0;
public SubstringEnumerable(strin
public string Current { get; pri
public bool MoveNext()
{
if (_state == 1) goto STATE1
if (_state == -1) goto END;
98. 内部実装(yield return)
• yield return → 状態記録、return、caseラベル
• 中断と再開
static IEnumerable<string> GetSubstrings(string s)
{
for (var len = s.Length; len >= 1; len--)
for (var i = 0; i <= s.Length - len; i++)
yield return s.Substring(i, len);
}
if (_state == 1) goto STATE1;
if (_state == -1) goto END;
_state = 1;
_len = _s.Length;
LOOP1BEGIN: ;
if (!(_len >= 1)) goto LOOP1END;
_i = 0;
LOOP2BEGIN: ;
if (!(_i <= _s.Length - _len)) go
_state = 1;
Current = _s.Substring(_i, _len);
return true;
STATE1: ;
_i++;
goto LOOP2BEGIN;
99. 内部実装(yield return)
• yield returnの部分、意味合いとしては†
switchで囲う
yield return以外の
場所はほぼ同じ
static IEnumerable<string> GetSubstrings(string s)
{
for (var len = s.Length; len >= 1; len--)
for (var i = 0; i <= s.Length - len; i++)
yield return s.Substring(i, len);
}
yield return x;
switch(_state)
{
case 0:
for (_len = _s.Length; _len >= 1; _len--)
for (_i = 0; _i <= _s.Length - _len; _i++)
{
_state = 1;
Current = _s.Substring(_i, _len);
return true;
case 1:;
}
_state = -1;
}
_state = 1;
Current = x;
return true;
case 1:;
† forループ内にラベル張れないからさっきみたいな複雑なコードになるけども
119. 多重ディスパッチ
• x, yの両方の型で動的に分岐
• 仮想メソッドでは(素直には)できない
static class Extensions
{
public static string Dispatch(this Base x, Base y)
{
動的な呼び出し
return (string)X((dynamic)x, (dynamic)y);
}
static string X(A x, A y) { return "A - A"; }
static string X(A x, B y) { return "A - B"; }
static string X(Base x, Base y) { return "others"; }
}
120. 多重ディスパッチ
• 呼び出し例
static void Main()
{
Dispatch(new A(),
Dispatch(new A(),
Dispatch(new B(),
Dispatch(new B(),
}
new
new
new
new
A());
B());
B());
A());
//
//
//
//
A - A
A - B
others
others
static void Dispatch(Base x, Base y)
{
Console.WriteLine(x.Dispatch(y));
}
121. ダック タイピング
• 静的な型に対して
class Point
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return "Point(" + X + ", " + Y + ")";
}
}
122. ダック タイピング
• 同じ名前のメンバーを持つ別の型をまとめて処
理
static class Extensions
{
public static void CopyTo<T, U>(this T p, U q)
{
dynamic x = p;
dynamic y = q;
y.X = x.X;
X, Yを持つ任意
y.Y = x.Y;
の型に使える
}
}
123. ダック タイピング
• 呼び出し例
var p = new Point();
new { X = 10, Y = 20 }.CopyTo(p);
Console.WriteLine(p);
124. DLR連携
• DLR (Dynamic Language Runtime)
• 例: IronPython
var py = IronPython.Hosting.Python.CreateEngine();
dynamic p = py.Execute("['a', 'b', 1, 2]");
for (var i = 0; i < 4; i++)
Console.WriteLine(p[i]);
• DLRは内部的に.NETの型を生成してるので内部実装
的にはこれも「静的な型に対する動的コード生成」
136. 同期処理
if (Check1.IsChecked)
{
var result = Dialog.ShowDialog("確認 1", "1つ目の確認作業");
if (!result) return false;
}
if (Check2.IsChecked)
{
var result = Dialog.ShowDialog("確認 2", "2つ目の確認作業");
if (!result) return false;
}
if (Check3.IsChecked)
{
var result = Dialog.ShowDialog("確認 3", "3つ目の確認作業");
if (!result) return false;
}
return true;
138. 非同期処理(C# 5.0)
if (this.Check1.IsChecked ?? false)
{
var result = await Dialog.ShowDialogAsync("確認 1", "1つ目の確認作業");
if (!result) return false;
}
if (this.Check2.IsChecked ?? false)
{
var result = await Dialog.ShowDialogAsync("確認 2", "2つ目の確認作業");
if (!result) return false;
}
if (this.Check3.IsChecked ?? false)
{
var result = await Dialog.ShowDialogAsync("確認 3", "3つ目の確認作業");
if (!result) return false;
}
return true;
• 同期処理と比べてawait演算子が増えただけ
• ダイアログの数が増えても平気
144. もう少し低レイヤーな話
• Taskクラス
async Task<int> Method()
{
var x = await task1;
var y = await task2;
}
_state = 1;
if (!task1.IsCompleted)
{
task1.ContinueWith(a);
return;
}
case 1:
var x = task1.Result;
• スレッド機能だけあればいいわけじゃない
• Task Pool、同期コンテキストとか
145. スレッド
• 非同期処理の最も低レイヤーな部分
• ただし、高負荷
for (int i = 0; i < 1000; i++)
{
var t = new Thread(Worker);
t.Start();
}
1000個の処理を同時実行
• 細々と大量の処理(タスク)をこなすには向かない
• 切り替え(コンテキスト スイッチ)のコストが高すぎる
165. C# 6.0 (予定)の例
Primary Constructor / Property Expressions
public class Point(int x, int y)
{
public int X => x;
immutableな型を作りやすく
public int Y => y;
}
Declaration Expressions
「式」で書けることの幅が広がる
while ((var line = stream.ReadLine()) != null)
line ...
if ((var x = obj as Point) != null)
x ...