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
値型のメンバーのところ
だけはアドレス取れる
差分ダウンロード
※ 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
インストール機
数値でのフィールド参照
• C#で擬似的に書くと
static intGetVolume(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)
とはいえ、いろいろ窮屈
• genericsでは、インターフェイス制約かけない
とメソッドすら呼べない
static TypeMax<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
イテレーター ブロック
• C++的な意味のイテレーターの生成を楽にする
std::vector<int>v{ 1, 2, 3, 4 };
for (auto p = v.begin(); p != v.end(); ++p)
std::cout << *p << std::endl;
こういうの
• 使う側(forループ側)は楽でいいんだけども
• 実装側(vector_iteratorの中身)はめんどくさい
これを楽にする
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)
• yieldreturn → 状態記録、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)
• yieldreturnの部分、意味合いとしては†
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ループ内にラベル張れないからさっきみたいな複雑なコードになるけども
多重ディスパッチ
• 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 voidMain()
{
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.
ダック タイピング
• 静的な型に対して
classPoint
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return "Point(" + X + ", " + Y + ")";
}
}
122.
ダック タイピング
• 同じ名前のメンバーを持つ別の型をまとめて処
理
staticclass 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.
ダック タイピング
• 呼び出し例
varp = new Point();
new { X = 10, Y = 20 }.CopyTo(p);
Console.WriteLine(p);
124.
DLR連携
• DLR (DynamicLanguage 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の型を生成してるので内部実装
的にはこれも「静的な型に対する動的コード生成」
同期処理
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;
非同期処理(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演算子が増えただけ
• ダイアログの数が増えても平気
参考: C#のイテレーター(再)
• 中断と再開
classMethodEnumerator : IEnumerator<int>
{
public int Current { get; private set; }
private int _state = 0;
public bool MoveNext()
{
switch (_state)
{
case 0:
状態の記録
Current = 1;
Current = 1;
_state = 1;
_state = 1;
return true;
中断
return 1:
case true;
case 1: = 2;
Current
_state = 2;
return true; 再開用のラベル
IEnumerable<int> Method()
{
yield return 1;
yield return 2;
case 2:
}
}
}
}
default:
return false;
141.
基本的な考え方
• 概念としては イテレーター+継続呼び出し
状態の記録
asyncTask<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;
結果の受け取り
142.
実際の展開結果
• 実際はもう少し複雑
• Awaiterというものを介する(Awaitableパターン)
_state= 1;
var awaiter1 = task1.GetAwaiter();
if (!awaiter1.IsCompleted)
{
awaiter1.OnCompleted(a); • Awaiterを自作することで、
awaitの挙動を変更可能
return;
}
• Task以外もawait可能
case 1:
var x = awaiter1.GetResult();
もう少し低レイヤーな話
• 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個の処理を同時実行
• 細々と大量の処理(タスク)をこなすには向かない
• 切り替え(コンテキスト スイッチ)のコストが高すぎる
C# 6.0 (予定)の例
PrimaryConstructor / 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 ...