Note
ãã®ããŒãžã«ã¢ã¯ã»ã¹ããã«ã¯ãæ¿èªãå¿ èŠã§ãã ãµã€ã³ã€ã³ãŸãã¯ãã£ã¬ã¯ããªã®å€æŽã詊ãããšãã§ããŸãã
ãã®ããŒãžã«ã¢ã¯ã»ã¹ããã«ã¯ãæ¿èªãå¿ èŠã§ãã ãã£ã¬ã¯ããªã®å€æŽã詊ãããšãã§ããŸãã
èšè¿°ãã C# ã³ãŒãã®ã»ãšãã©ã¯ãæ€èšŒå¯èœã«å®å šãªã³ãŒãã§ãã å®å šãªã³ãŒãã¯.NETããŒã«ã§ã³ãŒããå®å šã§ããããšã確èªã§ããããšãæå³ããŸãã äžè¬ã«ãå®å šãªã³ãŒãã¯ãã€ã³ã¿ãŒã䜿çšããŠã¡ã¢ãªã«çŽæ¥ã¢ã¯ã»ã¹ããŸããã ãŸããçã¡ã¢ãªã¯å²ãåœãŠãããŸããã 代ããã«ãããŒãžã ãªããžã§ã¯ããäœæãããŸãã
C# èšèªãªãã¡ã¬ã³ã¹ã«ã¯ãC# èšèªã®ææ°ãªãªãŒã¹ ããŒãžã§ã³ãèšèŒãããŠããŸãã ãŸããä»åŸã®èšèªãªãªãŒã¹ã®ãããªã㯠ãã¬ãã¥ãŒã®æ©èœã«é¢ããåæããã¥ã¡ã³ããå«ãŸããŠããŸãã
ãã®ããã¥ã¡ã³ãã§ã¯ãèšèªã®æåŸã® 3 ã€ã®ããŒãžã§ã³ãŸãã¯çŸåšã®ãããªã㯠ãã¬ãã¥ãŒã§æåã«å°å ¥ãããæ©èœãç¹å®ããŸãã
ãã³ã
C# ã§æ©èœãåããŠå°å ¥ãããææã確èªããã«ã¯ã C# èšèªããŒãžã§ã³å±¥æŽã«é¢ããèšäºãåç §ããŠãã ããã
C# ã§ã¯ãunsafeã³ãŒããèšè¿°ã§ãã ã³ã³ããã¹ãããµããŒããããŠããŸãã å®å
šã§ãªãã³ãŒãã¯å¿
ãããå±éºã§ã¯ãããŸããã.NETããŒã«ã§ã¯å®å
šæ§ãæ€èšŒã§ããªãã³ãŒãã«ãããŸããã å®å
šã§ãªãã³ãŒãã䜿çšããŠããã€ã³ã¿ãŒãå¿
èŠãšãããã€ãã£ã颿°ãåŒã³åºããå Žåã«ãã£ãŠã¯é
åå¢çãã§ãã¯ãåé¿ããçŽæ¥ã¡ã¢ãª ã¢ã¯ã»ã¹ã«ãã£ãŠããã©ãŒãã³ã¹ãåäžãããŸãã å®å
šã§ãªãã³ãŒãã§ã¯ãã»ãã¥ãªãã£ãšå®å®æ§ã®ãªã¹ã¯ãçºçããŸãã
unsafe ã³ã³ããã¹ããå«ãã³ãŒããã³ã³ãã€ã«ããã«ã¯ãAllowUnsafeBlocks ã³ã³ãã€ã© ãªãã·ã§ã³ã远å ããŸãã
C# ã§ã¯ãå®å šã§ãªãã³ãŒããšããŠã«ãŠã³ãããã 2 ã€ã®ã¢ãã«ãå®çŸ©ãããŠããŸããå ã®ã¢ãã«ãšãC# 15 ãš .NET 11 ã§ãã¬ãã¥ãŒæ®µéã«ããæŽæ°ãããã¡ã¢ãªå®å šã¢ãã«ã§ãã 2 ã€ã®ã¢ãã«ã®éãã«ã€ããŠã¯ã å®å šã§ãªãã³ãŒãã® 2 ã€ã®ã¢ãã«ãåç §ããŠãã ããã
C# ã§ã®å®å šã§ãªãã³ãŒãã®ãã¹ã ãã©ã¯ãã£ã¹ã«ã€ããŠã¯ãã å®å šã§ãªãã³ãŒãã®ãã¹ã ãã©ã¯ãã£ã¹ããåç §ããŠãã ããã
å®å šã§ãªãã³ãŒãã® 2 ã€ã®ã¢ãã«
C# ã§ã¯ãå®å
šã§ãªãã³ãŒãçšã® 2 ã€ã®ã¢ãã«ãå®çŸ©ãããŠããŸãã å®éã®ã¢ãã«ã¯ã unsafe ã³ã³ããã¹ããå¿
èŠãšããæäœãšãã¡ã³ããŒã® unsafe 修食åãåŒã³åºãå
ã«ã©ã®ããã«åœ±é¿ããããæ±ºå®ããŸãã
-
å
ã®å®å
šã§ãªãã¢ãã«:
unsafeã³ã³ããã¹ã㯠ããã€ã³ã¿ãŒç¹åŸŽã®ååšãã«ããŒããŸãã ãã€ã³ã¿ãŒåã®å®£èšã倿°ã®ã¢ãã¬ã¹ã®ååŸããã€ã³ã¿ãŒã®éåç §ãstackallocåŒã®ãã€ã³ã¿ãŒãžã®å€æããŸãã¯sizeofã³ã³ããã¹ãå ã§ã®ã¿ä»»æã®åãžã®unsafeã®é©çšãè¡ããŸãã (å®å šãªã³ãŒãã§ã¯ãstackallocãŸãã¯Span<T>ã«å²ãåœãŠãããReadOnlySpan<T>åŒã䜿çšã§ããŸã)ãåãã¡ã³ããŒããŸãã¯ãããã¯ã®unsafe修食åã¯ããã®ã³ã³ããã¹ãã確ç«ããŸãããåŒã³åºãå ã«ã¯çŸ©åãè² ããŸããã C# 1.0 ã§ã¯ãã®ã¢ãã«ãå°å ¥ãããæ¢å®å€ã®ãŸãŸã§ãã -
ã¡ã¢ãªå®å
šæ§ã¢ãã«ã®æŽæ°:
unsafeã³ã³ããã¹ãã¯ã ã©ã³ã¿ã€ã ã管çããŠããªãã¡ã¢ãªã«ã¢ã¯ã»ã¹ããæäœã察象ãšããŠããŸãã ãã€ã³ã¿ãŒã®ååšã¯å®å šã§ã¯ãããŸããããã€ã³ã¿ãŒã®éåç §ã¯æ¬¡ã®å€ã§ãã ã¡ã³ããŒã®unsafe修食åã¯ãåŒã³åºãå ã«å®å šæ§ãç£æ»ãã矩åãäŒéããã³ã³ãã©ã¯ãã«ãªããŸãã ãã®ã¢ãã«ã¯ãC# 15 ããã³ .NET 11 ã§ãã¬ãã¥ãŒæ®µéã«ãããŸãã
次ã®è¡šã§ã¯ãåã¢ãã«ã§ unsafe ã³ã³ããã¹ããå¿
èŠãšããæäœãæ¯èŒããŸãã
| Operation | å ã®ã¢ãã« | ã¢ãã«ã®æŽæ° |
|---|---|---|
ãã€ã³ã¿ãŒåã宣èšãããã & |
èŠæ± unsafe |
å®å šãªã³ãŒãã§èš±å¯ |
fixed ã¹ããŒãã¡ã³ã |
èŠæ± unsafe |
å®å šãªã³ãŒãã§èš±å¯ |
stackallocåŒããã€ã³ã¿ãŒã«å€æãã |
èŠæ± unsafe |
å®å šãªã³ãŒãã§èš±å¯ |
ã¢ã³ãããŒãžåã® sizeof æŒç®å |
èŠæ± unsafe |
å®å šãªã³ãŒãã§èš±å¯ |
ãã€ã³ã¿ãŒéæ¥åç
§ (*p)ãã¡ã³ã㌠ã¢ã¯ã»ã¹ (p->m)ããŸãã¯èŠçŽ ã¢ã¯ã»ã¹ (p[i]) |
èŠæ± unsafe |
èŠæ± unsafe |
| 颿°ãã€ã³ã¿ãŒã®åŒã³åºã | èŠæ± unsafe |
èŠæ± unsafe |
| åºå®ãµã€ãº ãããã¡ãŒã§ã®èŠçŽ ã¢ã¯ã»ã¹ | èŠæ± unsafe |
èŠæ± unsafe |
ããŒã¯ãããã¡ã³ããŒãåŒã³åºã unsafe |
åŒã³åºãå ã®èŠä»¶ãªã | èŠæ± unsafe |
ãã¬ãã¥ãŒæ§æãšãã€ã³ã¿ãŒã®ç·©åãæå¹ã«ããã«ã¯ã.NET 11 SDK ã䜿çšããLangVersion ã³ã³ãã€ã© ãªãã·ã§ã³ãpreviewã«èšå®ããŸãã åŒã³åºãå
ã®çŸ©åãå«ãæŽæ°ãããèŠåãæå¹ã«ããã«ã¯ãã æŽæ°ãããã¡ã¢ãªå®å
šèŠåãæå¹ã«ããããåç
§ããŠãã ããã
å ã®å®å šã§ãªãã¢ãã«
å
ã®ã¢ãã«ã§ã¯ã unsafe ããŒã¯ãŒãã¯ãåãã¡ã³ããŒããŸãã¯ãããã¯ã«å®å
šã§ãªãã³ã³ããã¹ãã確ç«ãããã®ã³ã³ããã¹ãã«ãã£ãŠã次ã®ã»ã¯ã·ã§ã³ã§èª¬æãããã€ã³ã¿ãŒæ©èœã®ããã¯ãè§£é€ãããŸãã
unsafe修食åã¯ãããŒã¯ãããã³ãŒããå®è¡ã§ããæäœã®ã¿ã倿ŽããŸããåŒã³åºãå
ã«ã¯å¿
èŠãããŸããã ãããã®äŸã®ãããããã³ã³ãã€ã«ããã«ã¯ã AllowUnsafeBlocks ã³ã³ãã€ã© ãªãã·ã§ã³ãèšå®ããŸãã
ãã€ã³ã¿ãŒå
å®å šã§ãªãã³ã³ããã¹ãã§ã¯ãåã«ã¯ãå€åãŸãã¯åç §åã«å ããŠããã€ã³ã¿ãŒåãæå®ã§ããŸãã ãã€ã³ã¿ãŒå宣èšã¯ã次ã®ããããã®åœ¢åŒã«ãªããŸãã
type* identifier;
void* identifier; //allowed but not recommended
ãã€ã³ã¿ãŒåã® * ã®åã«æå®ããå㯠ãåç
§å
ã®åã§ãã
ãã€ã³ã¿ãŒå㯠ãªããžã§ã¯ãããç¶æ¿ããããã€ã³ã¿ãŒåãš objectã®éã«å€æã¯ååšããŸããã ãŸããããã¯ã¹åãšããã¯ã¹åè§£é€ããã€ã³ã¿ãŒããµããŒãããŸããã ãã ããç°ãªããã€ã³ã¿ãŒåéãããã³ãã€ã³ã¿ãŒåãšæŽæ°åã®éã§å€æã§ããŸãã
åã宣èšã§è€æ°ã®ãã€ã³ã¿ãŒã宣èšããå Žåã¯ãåºã«ãªãåãšå
±ã«ã¢ã¹ã¿ãªã¹ã¯ (*) ã®ã¿ãèšè¿°ããŸãã åãã€ã³ã¿ãŒåã®ãã¬ãã£ãã¯ã¹ãšããŠã¯äœ¿çšãããŸããã äŸãã°æ¬¡ãæããããŸãã
int* p1, p2, p3; // Ok
int *p1, *p2, *p3; // Invalid in C#
ã¬ããŒãž ã³ã¬ã¯ã¿ãŒã¯ããªããžã§ã¯ããæããã€ã³ã¿ãŒåããããã©ããã远跡ããŸããã åç §å ããããŒãžã ããŒãå ã®ãªããžã§ã¯ã (ã©ã ãåŒãŸãã¯å¿åããªã²ãŒãã«ãã£ãŠãã£ããã£ãããããŒã«ã«å€æ°ãå«ã) ã§ããå Žåã¯ããã€ã³ã¿ãŒã䜿çšãããŠããéãããªããžã§ã¯ãã ãã³çã ããå¿ èŠããããŸãã
MyType*åã®ãã€ã³ã¿ãŒå€æ°ã®å€ã¯ãMyTypeåã®å€æ°ã®ã¢ãã¬ã¹ã§ãã ãã€ã³ã¿ãŒå宣èšã®äŸã次ã«ç€ºããŸãã
-
int* p:pã¯æŽæ°ãžã®ãã€ã³ã¿ãŒã§ãã -
int** p:pã¯ãæŽæ°ãžã®ãã€ã³ã¿ãŒã®ãã€ã³ã¿ãŒã§ãã -
int*[] p:pã¯ãæŽæ°ãžã®ãã€ã³ã¿ãŒã® 1 次å é åã§ãã -
char* p:p㯠char ãžã®ãã€ã³ã¿ãŒã§ãã -
void* p:pã¯äžæãªåãžã®ãã€ã³ã¿ãŒã§ãã
ãã€ã³ã¿ãŒéæ¥æŒç®å * ã䜿çšããŠããã€ã³ã¿ãŒå€æ°ãæãå Žæã«ããã³ã³ãã³ãã«ã¢ã¯ã»ã¹ã§ããŸãã ããšãã°ã次ã®å®£èšãèããŠã¿ãŸãããã
int* myVariable;
åŒ*myVariableã¯ãintã«å«ãŸããã¢ãã¬ã¹ã«ããmyVariable倿°ã衚ããŸãã
fixed ã¹ããŒãã¡ã³ãã®èšäºã«ã¯ãããã€ãã®ãã€ã³ã¿ãŒã®äŸããããŸãã æ¬¡ã®äŸã§ã¯ã unsafe ããŒã¯ãŒããš fixed ã¹ããŒãã¡ã³ãã䜿çšããå
éšãã€ã³ã¿ãŒãã€ã³ã¯ãªã¡ã³ãããæ¹æ³ã瀺ããŸãã ãã®ã³ãŒããã³ã³ãœãŒã« ã¢ããªã±ãŒã·ã§ã³ã® Main 颿°ã«è²Œãä»ããŠå®è¡ã§ããŸãã ãããã®äŸã¯ã AllowUnsafeBlocks ã³ã³ãã€ã© ãªãã·ã§ã³ ã»ããã䜿çšããŠã³ã³ãã€ã«ããå¿
èŠããããŸãã
// Normal pointer to an object.
int[] a = [10, 20, 30, 40, 50];
// Must be in unsafe code to use interior pointers.
unsafe
{
// Must pin object on heap so that it doesn't move while using interior pointers.
fixed (int* p = &a[0])
{
// p is pinned as well as object, so create another pointer to show incrementing it.
int* p2 = p;
Console.WriteLine(*p2);
// Incrementing p2 bumps the pointer by four bytes due to its type ...
p2 += 1;
Console.WriteLine(*p2);
p2 += 1;
Console.WriteLine(*p2);
Console.WriteLine("--------");
Console.WriteLine(*p);
// Dereferencing p and incrementing changes the value of a[0] ...
*p += 1;
Console.WriteLine(*p);
*p += 1;
Console.WriteLine(*p);
}
}
Console.WriteLine("--------");
Console.WriteLine(a[0]);
/*
Output:
10
20
30
--------
10
11
12
--------
12
*/
鿥æŒç®åã void*åã®ãã€ã³ã¿ãŒã«é©çšããããšã¯ã§ããŸããã ãã ãããã£ã¹ãã䜿çšã㊠void ãã€ã³ã¿ãŒãä»ã®ãã€ã³ã¿ãŒåã«å€æãããã®éãè¡ãããšãã§ããŸãã
ãã€ã³ã¿ãŒã¯ nullã§ããŸãã 鿥æŒç®åã null ãã€ã³ã¿ãŒã«é©çšãããšãå®è£
ã§å®çŸ©ãããåäœãçºçããŸãã
ã¡ãœããéã§ãã€ã³ã¿ãŒãæž¡ããšãæªå®çŸ©ã®åäœãçºçããå¯èœæ§ããããŸãã
inãoutããŸãã¯refãã©ã¡ãŒã¿ãŒãä»ããŠããŸãã¯é¢æ°ã®çµæãšããŠããŒã«ã«å€æ°ãžã®ãã€ã³ã¿ãŒãè¿ãã¡ãœããã«ã€ããŠèããŠã¿ãŸãããã ãã€ã³ã¿ãŒãåºå®ãããã¯ã«èšå®ãããŠããå Žåããã€ã³ã¿ãŒãæã倿°ãåºå®ãããªããªãå¯èœæ§ããããŸãã
次ã®è¡šã«ãå®å šã§ãªãã³ã³ããã¹ãã§ãã€ã³ã¿ãŒãæäœã§ããæŒç®åãšã¹ããŒãã¡ã³ãã瀺ããŸãã
| ãªãã¬ãŒã¿ãŒ/ã¹ããŒãã¡ã³ã | çšé |
|---|---|
* |
ãã€ã³ã¿ãŒã®éæ¥åç §ãå®è¡ããŸãã |
-> |
ãã€ã³ã¿ãŒãä»ããŠæ§é äœã®ã¡ã³ããŒã«ã¢ã¯ã»ã¹ããŸãã |
[] |
ãã€ã³ã¿ãŒã®ã€ã³ããã¯ã¹ãäœæããŸãã |
& |
倿°ã®ã¢ãã¬ã¹ãååŸããŸãã |
++ ãš -- |
ãã€ã³ã¿ãŒãã€ã³ã¯ãªã¡ã³ãããã³ãã¯ãªã¡ã³ãããŸãã |
+ ãš - |
ãã€ã³ã¿ãŒã®ç®è¡æŒç®ãå®è¡ããŸãã |
==ã!=ã<ã>ã<=ã>= |
ãã€ã³ã¿ãŒãæ¯èŒããŸãã |
stackalloc |
ã¹ã¿ãã¯ã«ã¡ã¢ãªãå²ãåœãŠãŸãã |
fixed ã¹ããŒãã¡ã³ã |
ã¢ãã¬ã¹ãèŠã€ããããšãã§ããããã«ã倿°ãäžæçã«ä¿®æ£ããŸãã |
ãã€ã³ã¿ãŒé¢é£æŒç®åã®è©³çްã«ã€ããŠã¯ãã ãã€ã³ã¿ãŒé¢é£ã®æŒç®åããåç §ããŠãã ããã
ãã€ã³ã¿ãŒåã¯ãæé»çã« void* åã«å€æã§ããŸãã ãã€ã³ã¿ãŒåã«ã¯ã nullå€ãå²ãåœãŠãããšãã§ããŸãã ãã£ã¹ãåŒã䜿çšããŠãä»»æã®ãã€ã³ã¿ãŒåãä»ã®ãã€ã³ã¿ãŒåã«æç€ºçã«å€æã§ããŸãã ä»»æã®æŽæ°åããã€ã³ã¿ãŒåã«å€æããããšããä»»æã®ãã€ã³ã¿ãŒåãæŽæ°åã«å€æããããšãã§ããŸãã ãããã®å€æã«ã¯ãæç€ºçãªãã£ã¹ããå¿
èŠã§ãã
次ã®äŸã§ã¯ã int* ã byte*ã«å€æããŸãã ãã€ã³ã¿ãŒã倿°ã®æäžäœã®ã¢ãã¬ã¹æå®ãã€ããæããŠããããšã«æ³šæããŠãã ããã çµæãé£ç¶ããŠã€ã³ã¯ãªã¡ã³ããããšã int ã®ãµã€ãº (4 ãã€ã) ãŸã§ã倿°ã®æ®ãã®ãã€ãã衚瀺ã§ããŸãã
int number = 1024;
unsafe
{
// Convert to byte:
byte* p = (byte*)&number;
System.Console.Write("The 4 bytes of the integer:");
// Display the 4 bytes of the int variable:
for (int i = 0 ; i < sizeof(int) ; ++i)
{
System.Console.Write(" {0:X2}", *p);
// Increment the pointer:
p++;
}
System.Console.WriteLine();
System.Console.WriteLine($"The value of the integer: {number}");
/* Output:
The 4 bytes of the integer: 00 04 00 00
The value of the integer: 1024
*/
}
åºå®ãµã€ãº ãããã¡ãŒ
é
åã¯åç
§åã§ãããããã»ãŒã ã³ãŒãã§ã¯ãé
åã§ããæ§é äœãã£ãŒã«ãã«ã¯ãèŠçŽ èªäœã§ã¯ãªããé
åã®èŠçŽ ãžã®åç
§ã®ã¿ãæ ŒçŽãããŸãã
structã¯åç
§ã§ãããããæ¬¡ã®pathNameã®ãµã€ãºã¯é
åå
ã®èŠçŽ ã®æ°ã«äŸåããŸããã
public struct PathArray
{
public char[] pathName;
private int reserved;
}
æ§é äœèªäœã®å
éšã«é
åã®å
å®¹ãæ ŒçŽããã«ã¯ã fixed ããŒã¯ãŒãã䜿çšã㊠åºå®ãµã€ãºã®ãããã¡ãŒã宣èšããŸãã
fixed ããŒã¯ãŒãã«ã¯ãunsafe ã³ã³ããã¹ããå¿
èŠã§ãã åºå®ãµã€ãºãããã¡ãŒã¯ãä»ã®èšèªãŸãã¯ãã©ãããã©ãŒã ã®ããŒã¿ ãœãŒã¹ãšçžäºéçšããã¡ãœãããèšè¿°ããå Žåã«äŸ¿å©ã§ãã åºå®ãµã€ãºã®ãããã¡ãŒã¯ãéåžžã®æ§é äœã¡ã³ããŒã«èš±å¯ãããŠããä»»æã®å±æ§ãŸãã¯ä¿®é£Ÿåãåãåãããšãã§ããŸãã å¯äžã®å¶éã¯ãé
åã®åã boolã byteã charã shortã intã longã sbyteã ushortã uintã ulongã floatããŸã㯠doubleã§ããå¿
èŠããããšããããšã§ãã
private fixed char name[30];
次ã®äŸã§ã¯ã fixedBuffer é
åã®ãµã€ãºã¯åºå®ãããŠããŸãã
fixed ã¹ããŒãã¡ã³ãã䜿çšããŠæåã®èŠçŽ ãžã®ãã€ã³ã¿ãŒãååŸãããã®ãã€ã³ã¿ãŒãä»ããŠé
åã®èŠçŽ ã«ã¢ã¯ã»ã¹ããŸãã
fixed ã¹ããŒãã¡ã³ãã¯ãfixedBuffer ã€ã³ã¹ã¿ã³ã¹ ãã£ãŒã«ããã¡ã¢ãªå
ã®ç¹å®ã®å Žæã«ãã³çãããŸãã
internal unsafe struct Buffer
{
public fixed char fixedBuffer[128];
}
internal unsafe class Example
{
public Buffer buffer = default;
}
private static void AccessEmbeddedArray()
{
var example = new Example();
unsafe
{
// Pin the buffer to a fixed location in memory.
fixed (char* charPtr = example.buffer.fixedBuffer)
{
*charPtr = 'A';
}
// Access safely through the index:
char c = example.buffer.fixedBuffer[0];
Console.WriteLine(c);
// Modify through the index:
example.buffer.fixedBuffer[0] = 'B';
Console.WriteLine(example.buffer.fixedBuffer[0]);
}
}
é
å char 128 èŠçŽ ã®ãµã€ãºã¯ 256 ãã€ãã§ãã åºå®ãµã€ãºã® char ãããã¡ãŒã¯ããšã³ã³ãŒãã«é¢ä¿ãªããåžžã« 1 æåããã 2 ãã€ããåãåããŸãã ãã®é
åãµã€ãºã¯ã CharSet = CharSet.Auto ãŸã㯠CharSet = CharSet.Ansiãæã€ API ã¡ãœãããŸãã¯æ§é äœã« char ãããã¡ãŒãããŒã·ã£ãªã³ã°ãããŠããå Žåã§ãåãã§ãã 詳现ã«ã€ããŠã¯ãCharSetãåç
§ããŠãã ããã
åã®äŸã§ã¯ããã³çãããã« fixed ãã£ãŒã«ãã«ã¢ã¯ã»ã¹ããæ¹æ³ã瀺ããŸãã ãã 1 ã€ã®äžè¬çãªåºå®ãµã€ãºé
å㯠ãããŒã« é
åã§ãã
boolé
åå
ã®èŠçŽ ã®ãµã€ãºã¯åžžã« 1 ãã€ãã§ãã
bool é
åã¯ããããé
åãŸãã¯ãããã¡ãŒã®äœæã«ã¯é©ããŠããŸããã
åºå®ãµã€ãºã®ãããã¡ãŒã¯ã System.Runtime.CompilerServices.UnsafeValueTypeAttributeã§ã³ã³ãã€ã«ãããŸããããã«ãããåã«ãªãŒããŒãããŒããå¯èœæ§ãããã¢ã³ãããŒãžé
åãå«ãŸããŠããããšãå
±éèšèªã©ã³ã¿ã€ã (CLR) ã«æç€ºããŸãã
stackalloc ã䜿çšããŠå²ãåœãŠãããã¡ã¢ãªã§ã¯ãCLR ã®ãããã¡ãŒ ãªãŒããŒã©ã³æ€åºæ©èœãèªåçã«æå¹ã«ãªããŸãã åã®äŸã¯ãåºå®ãµã€ãºã®ãããã¡ãŒã unsafe structã«ã©ã®ããã«ååšãããã瀺ããŠããŸãã
internal unsafe struct Buffer
{
public fixed char fixedBuffer[128];
}
Bufferçšã«ã³ã³ãã€ã©ã«ãã£ãŠçæããã C# ã®å±æ§ã¯æ¬¡ã®ãšããã§ãã
internal struct Buffer
{
[StructLayout(LayoutKind.Sequential, Size = 256)]
[CompilerGenerated]
[UnsafeValueType]
public struct <fixedBuffer>e__FixedBuffer
{
public char FixedElementField;
}
[FixedBuffer(typeof(char), 128)]
public <fixedBuffer>e__FixedBuffer fixedBuffer;
}
åºå®ãµã€ãºãããã¡ãŒã¯ã次ã®ç¹ã§éåžžã®é åãšã¯ç°ãªããŸãã
-
unsafeã³ã³ããã¹ãã§ã®ã¿äœ¿çšã§ããŸãã - æ§é äœã®ã€ã³ã¹ã¿ã³ã¹ ãã£ãŒã«ãã®ã¿ãæå®ã§ããŸãã
- ãããã¯åžžã«ãã¯ãã«ãŸã㯠1 次å é åã§ãã
- 宣èšã«ã¯ã
fixed char id[8]ãªã©ã®é·ããå«ããå¿ èŠããããŸããfixed char id[]ã䜿çšããããšã¯ã§ããŸããã
颿°ãã€ã³ã¿ãŒ
C# ã«ã¯ãå®å
šãªé¢æ°ãã€ã³ã¿ãŒ ãªããžã§ã¯ããå®çŸ©ããããã® delegate åãçšæãããŠããŸãã ããªã²ãŒããåŒã³åºãã«ã¯ã System.Delegate ããæŽŸçããåãã€ã³ã¹ã¿ã³ã¹åãããã® Invoke ã¡ãœãããä»®æ³ã¡ãœããåŒã³åºãããå¿
èŠããããŸãã ãã®ä»®æ³åŒã³åºãã§ã¯ã callvirt IL åœä»€ã䜿çšãããŸãã ããã©ãŒãã³ã¹ ã¯ãªãã£ã«ã«ãªã³ãŒã ãã¹ã§ã¯ã calli IL åœä»€ã䜿çšããæ¹ãå¹ççã§ãã
delegate*æ§æã䜿çšããŠã颿°ãã€ã³ã¿ãŒãå®çŸ©ã§ããŸãã ã³ã³ãã€ã©ã¯ãcalli ãªããžã§ã¯ããã€ã³ã¹ã¿ã³ã¹åããŠdelegateãåŒã³åºãã®ã§ã¯ãªããInvokeåœä»€ã䜿çšããŠé¢æ°ãåŒã³åºããŸãã æ¬¡ã®ã³ãŒãã§ã¯ãåãåã® 2 ã€ã®ãªããžã§ã¯ããçµåããããã« delegate ãŸã㯠delegate* ã䜿çšãã 2 ã€ã®ã¡ãœããã宣èšããŸãã æåã®ã¡ãœããã¯ã System.Func<T1,T2,TResult> ããªã²ãŒãåã䜿çšããŸãã 2 çªç®ã®ã¡ãœããã¯ãåããã©ã¡ãŒã¿ãŒãšæ»ãå€ã®åãæã€ delegate* 宣èšã䜿çšããŸãã
public static T Combine<T>(Func<T, T, T> combinator, T left, T right) =>
combinator(left, right);
public static unsafe T UnsafeCombine<T>(delegate*<T, T, T> combinator, T left, T right) =>
combinator(left, right);
次ã®ã³ãŒãã¯ãéçããŒã«ã«é¢æ°ã宣èšãããã®ããŒã«ã«é¢æ°ãžã®ãã€ã³ã¿ãŒã䜿çšã㊠UnsafeCombine ã¡ãœãããåŒã³åºãæ¹æ³ã瀺ããŠããŸãã
int product = 0;
unsafe
{
static int localMultiply(int x, int y) => x * y;
product = UnsafeCombine(&localMultiply, 3, 4);
}
äžèšã®ã³ãŒãã¯ã颿°ãã€ã³ã¿ãŒãšããŠã¢ã¯ã»ã¹ããã颿°ã«é¢ããããã€ãã®èŠåã瀺ããŠããŸãã
- 颿°ãã€ã³ã¿ãŒã¯ã
unsafeã³ã³ããã¹ãã§ã®ã¿å®£èšã§ããŸãã -
delegate*ã³ã³ããã¹ãã§delegate*ãåãåã (ãŸãã¯unsafeãè¿ã) ã¡ãœããã®ã¿ãåŒã³åºãããšãã§ããŸãã - 颿°ã®ã¢ãã¬ã¹ãååŸãã
&æŒç®åã¯ãstatic颿°ã§ã®ã¿èš±å¯ãããŸãã ãã®èŠåã¯ãã¡ã³ããŒé¢æ°ãšããŒã«ã«é¢æ°ã®äž¡æ¹ã«é©çšãããŸãã
æ§æã«ã¯ã delegate åã®å®£èšãšãã€ã³ã¿ãŒã®äœ¿çšãšã®äžŠåããããŸãã
*ã®delegateãµãã£ãã¯ã¹ã¯ã宣èšã颿°ãã€ã³ã¿ãŒã§ããããšã瀺ããŸãã ã¡ãœãã ã°ã«ãŒãã颿°ãã€ã³ã¿ãŒã«å²ãåœãŠãéã® & ã¯ãæäœãã¡ãœããã®ã¢ãã¬ã¹ãåãåããŸãã
ããŒã¯ãŒãã®delegate*ãšmanagedã䜿çšããŠãunmanagedã®åŒã³åºãèŠåãæå®ã§ããŸãã ããã«ã unmanaged 颿°ãã€ã³ã¿ãŒã®å Žåã¯ãåŒã³åºãèŠåãæå®ã§ããŸãã æ¬¡ã®å®£èšã¯ãããããã®äŸã瀺ããŠããŸãã æåã®å®£èšã§ã¯ãæ¢å®ã® managed åŒã³åºãèŠåã䜿çšãããŸãã æ¬¡ã® 4 ã€ã§ã¯ã unmanaged åŒã³åºãèŠåã䜿çšãããŸãã ãããããECMA 335 åŒã³åºãèŠå ( Cdeclã Stdcallã FastcallããŸã㯠Thiscall) ã®ãããããæå®ããŸãã æåŸã®å®£èšã§ã¯ã unmanaged åŒã³åºãèŠåã䜿çšãããã©ãããã©ãŒã ã®æ¢å®ã®åŒã³åºãèŠåãéžæããããã« CLR ã«æç€ºããŸãã CLR ã¯ãå®è¡æã«åŒã³åºãèŠåãéžæããŸãã
public static unsafe T ManagedCombine<T>(delegate* managed<T, T, T> combinator, T left, T right) =>
combinator(left, right);
public static unsafe T CDeclCombine<T>(delegate* unmanaged[Cdecl]<T, T, T> combinator, T left, T right) =>
combinator(left, right);
public static unsafe T StdcallCombine<T>(delegate* unmanaged[Stdcall]<T, T, T> combinator, T left, T right) =>
combinator(left, right);
public static unsafe T FastcallCombine<T>(delegate* unmanaged[Fastcall]<T, T, T> combinator, T left, T right) =>
combinator(left, right);
public static unsafe T ThiscallCombine<T>(delegate* unmanaged[Thiscall]<T, T, T> combinator, T left, T right) =>
combinator(left, right);
public static unsafe T UnmanagedCombine<T>(delegate* unmanaged<T, T, T> combinator, T left, T right) =>
combinator(left, right);
颿°ãã€ã³ã¿ãŒã®è©³çްã«ã€ããŠã¯ãC# èšèªä»æ§ã® 颿°ãã€ã³ã¿ãŒ ã»ã¯ã·ã§ã³ãåç §ããŠãã ããã
äŸ: ãã€ã³ã¿ãŒã䜿çšããŠãã€ãã®é åãã³ããŒãã
次ã®äŸã§ã¯ããã€ã³ã¿ãŒã䜿çšããŠãããé åããå¥ã®é åã«ãã€ããã³ããŒããŸãã
ãã®äŸã§ã¯ã unsafe ããŒã¯ãŒãã䜿çšããŸããããã«ããã Copy ã¡ãœããã§ãã€ã³ã¿ãŒã䜿çšã§ããŸãã
fixed ã¹ããŒãã¡ã³ãã¯ããœãŒã¹é
åãšã³ããŒå
é
åãžã®ãã€ã³ã¿ãŒã宣èšããŸãã
fixed ã¹ããŒãã¡ã³ãã¯ãã¬ããŒãž ã³ã¬ã¯ã·ã§ã³ãé
åãç§»åããªãããã«ãã¡ã¢ãªå
ã®ãœãŒã¹é
åãšã³ããŒå
é
åã®äœçœ®ãåºå®ããŸãã
fixed ãããã¯ã¯ããããã¯ã®ã¹ã³ãŒãå
ã®é
åã®ã¡ã¢ãª ãããã¯ããã³çãããŸãã ãã®äŸã® Copy ã¡ãœãã㯠unsafe ããŒã¯ãŒãã䜿çšããããã AllowUnsafeBlocks ã³ã³ãã€ã© ãªãã·ã§ã³ã䜿çšããŠã³ã³ãã€ã«ããå¿
èŠããããŸãã
ãã®äŸã§ã¯ã2 çªç®ã®ã¢ã³ãããŒãž ãã€ã³ã¿ãŒã§ã¯ãªãã€ã³ããã¯ã¹ã䜿çšããŠãäž¡æ¹ã®é
åã®èŠçŽ ã«ã¢ã¯ã»ã¹ããŸãã
pSourceãã€ã³ã¿ãŒãšpTarget ãã€ã³ã¿ãŒã®å®£èšã«ãããé
åããã³çããããŸãã
static unsafe void Copy(byte[] source, int sourceOffset, byte[] target,
int targetOffset, int count)
{
// If either array is not instantiated, you cannot complete the copy.
if ((source == null) || (target == null))
{
throw new System.ArgumentException("source or target is null");
}
// If either offset, or the number of bytes to copy, is negative, you
// cannot complete the copy.
if ((sourceOffset < 0) || (targetOffset < 0) || (count < 0))
{
throw new System.ArgumentException("offset or bytes to copy is negative");
}
// If the number of bytes from the offset to the end of the array is
// less than the number of bytes you want to copy, you cannot complete
// the copy.
if ((source.Length - sourceOffset < count) ||
(target.Length - targetOffset < count))
{
throw new System.ArgumentException("offset to end of array is less than bytes to be copied");
}
// The following fixed statement pins the location of the source and
// target objects in memory so that they will not be moved by garbage
// collection.
fixed (byte* pSource = source, pTarget = target)
{
// Copy the specified number of bytes from source to target.
for (int i = 0; i < count; i++)
{
pTarget[targetOffset + i] = pSource[sourceOffset + i];
}
}
}
static void UnsafeCopyArrays()
{
// Create two arrays of the same length.
int length = 100;
byte[] byteArray1 = new byte[length];
byte[] byteArray2 = new byte[length];
// Fill byteArray1 with 0 - 99.
for (int i = 0; i < length; ++i)
{
byteArray1[i] = (byte)i;
}
// Display the first 10 elements in byteArray1.
System.Console.WriteLine("The first 10 elements of the original are:");
for (int i = 0; i < 10; ++i)
{
System.Console.Write(byteArray1[i] + " ");
}
System.Console.WriteLine("\n");
// Copy the contents of byteArray1 to byteArray2.
Copy(byteArray1, 0, byteArray2, 0, length);
// Display the first 10 elements in the copy, byteArray2.
System.Console.WriteLine("The first 10 elements of the copy are:");
for (int i = 0; i < 10; ++i)
{
System.Console.Write(byteArray2[i] + " ");
}
System.Console.WriteLine("\n");
// Copy the contents of the last 10 elements of byteArray1 to the
// beginning of byteArray2.
// The offset specifies where the copying begins in the source array.
int offset = length - 10;
Copy(byteArray1, offset, byteArray2, 0, length - offset);
// Display the first 10 elements in the copy, byteArray2.
System.Console.WriteLine("The first 10 elements of the copy are:");
for (int i = 0; i < 10; ++i)
{
System.Console.Write(byteArray2[i] + " ");
}
System.Console.WriteLine("\n");
/* Output:
The first 10 elements of the original are:
0 1 2 3 4 5 6 7 8 9
The first 10 elements of the copy are:
0 1 2 3 4 5 6 7 8 9
The first 10 elements of the copy are:
90 91 92 93 94 95 96 97 98 99
*/
}
æŽæ°ãããã¡ã¢ãªå®å šã¢ãã« (ãã¬ãã¥ãŒ)
Important
æŽæ°ãããã¡ã¢ãªå®å šã¢ãã«ã¯ãC# 15 ããã³ .NET 11 ã®ãã¬ãã¥ãŒæ©èœã§ãã ã¢ã¯ãã£ãåã®æé ã«ã€ããŠã¯ãã æŽæ°ãããã¡ã¢ãªã»ãŒãã«ãŒã«ãæå¹ã«ããããåç §ããŠãã ããã å®å šãªèšèšã«ã€ããŠã¯ã ã¡ã¢ãªå®å šæ©èœã®ä»æ§ãåç §ããŠãã ããã
æŽæ°ãããã¢ãã«ã¯ãå
ã®ã¢ãã«ã 1 ã€ãšããŠæ±ã 2 ã€ã®äºæ (ãã€ã³ã¿ãŒ ã³ãŒãã® ååš ãšåŒã³åºãå
ãžã®å®å
šçŸ©åã® äŒé ) ãåé¢ããŸãã ã¡ã³ã㌠unsafe ããŒã¯ãããšããã®ã¡ã³ããŒã®æ¬äœå
ã®ãã€ã³ã¿ãŒãèš±å¯ãããã ãã§ãªããã¡ã³ã㌠ã¯å®å
šã§ã¯ãªããªããŸãããã®ããããã¹ãŠã®åŒã³åºãå
ããã®çŸ©åãäŒéããããæ€èšŒæžã¿ã®å®å
šãªåŒã³åºãå¯èœãªå¢çã®èåŸã«æåºããå¿
èŠããããŸãã ãã®åé¢ããµããŒãããããã«ãã¢ãã«ã§ã¯å®å
šã§ãªãã³ã³ããã¹ããçµã蟌ãŸããŸãããã€ã³ã¿ãŒã®ååšã¯å®å
šã§ã¯ãããŸãããã©ã³ã¿ã€ã ã管çããŠããªãã¡ã¢ãªã«ã¢ã¯ã»ã¹ããæäœã ãã§ãã çž®å°ã䜿çšãããšãå®å
šãªã³ãŒãã§ãã€ã³ã¿ãŒãä¿æãæž¡ããè¿ãããšãã§ããŸããã unsafe ã¯ãã¡ã¢ãªã®å®å
šæ§ã«å®éã«éåããå¯èœæ§ãããæäœãšã¡ã³ããŒãããŒã¯ããŸãã
Requires-unsafe ã¡ã³ããŒ
å
ã®ã¢ãã«ã§ã¯ãã¡ã³ããŒã® unsafe 修食åã¯ãã¡ã³ããŒã®ã·ã°ããã£ã𿬿å
ã®ãã€ã³ã¿ãŒã®ã¿ãèš±å¯ããŸãã åŒã³åºãå
ã«å®å
šæ§ã«ã€ããŠã¯éç¥ããŸããã æŽæ°ãããã¢ãã«ã¯ãåŒã³åºãå
ã«ä¿®é£Ÿåã®æå³ãäžããŸãã ã¡ã³ããŒã unsafeããŒã¯ãããšãã³ã³ãã€ã©ã¯ããã å¿
é ã»ãŒããšããŠæ±ããŸãããã¹ãŠã®åŒã³åºãå
㯠unsafe ã³ã³ããã¹ãããåŒã³åºãå¿
èŠãããããã®åŒã³åºãå
ã«å®å
šãç£æ»ãã矩åãç§»ããŸãã
ã¡ã³ããŒã·ã°ããã£ã® unsafe 修食åã¯ãæ¬æã®å®å
šã§ãªãã³ã³ããã¹ãã確ç«ããªããªããŸããã æ¬¡ã® 2 ã€ã®ããŒã«ãåå²ãããŸãã
- 眲åã®
unsafe修食åã¯ãåŒã³åºãå ã«çŸ©åãäŒéããŸãã - å
éš
unsafeãããã¯ã¯ãã¢ã³ãããŒãž ã¡ã¢ãªã«ã¢ã¯ã»ã¹ããæäœã®ã¹ã³ãŒããèšå®ããŸãã
次ã®ãã¬ãã¥ãŒã®äŸã§ã¯ã ReadInt32 ã¯å®å
šã§ã¯ãããŸããã ã·ã°ããã£ã¯ unsafe 修食åãæã¡ãå
éš unsafe ãããã¯ã¯éåç
§ãã©ããããŸãã
// Preview: requires the updated-memory-safety-rules feature.
public static unsafe int ReadInt32(byte* source)
{
unsafe
{
return *(int*)source;
}
}
åŒã³åºãå
ã¯ãç¬èªã® unsafe ãããã¯ã§åŒã³åºããã©ããããŸãã
// Preview
unsafe
{
int value = ReadInt32(buffer);
}
æŽæ°ãããã¢ãã«ã§ã¯ãããã€ãã®é¢é£ã«ãŒã«ã匷åãããŸãã
-
unsafe修食åã¯ãå宣èšãéçã³ã³ã¹ãã©ã¯ã¿ãŒãããã³ãã¡ã€ãã©ã€ã¶ãŒã§ãšã©ãŒãçæããŸããããã¯ã修食åã«éç¥ããåŒã³åºãå ããªãããã§ãã - ããªã²ãŒãã¯ååã§ãããããããªã²ãŒãã
unsafeã§ããŸããã - ãã©ã¡ãŒã¿ãŒãªãã®ã³ã³ã¹ãã©ã¯ã¿ãŒã
unsafeãããŠããåã¯ãåºæ¬åããã£ãŒã«ãåãªã©ã宣èšå ã®new()ãŸãã¯structå¶çŽãæºããããšã¯ã§ããŸããã åŒã§ã¯ãå®å šã§ãªãã³ã³ããã¹ãå ã®å¶çŽãæºããããšãã§ããŸããããšãã°ãBox<T>ã«new()å¶çŽããããNativeResourceã«å¿ é ã®å®å šã§ãªãã³ã³ã¹ãã©ã¯ã¿ãŒãããå Žåã«unsafe { var box = new Box<NativeResource>(); }ããŸãã ãã®ãã§ãã¯ã¯ãæ¡åŒµãããã¯ãšæ¡åŒµã¡ãœããã®ååŒæ°ãå«ãããžã§ããªãã¯åãšã¡ãœããã®ã€ã³ã¹ã¿ã³ã¹åã«é©çšãããŸãã å®å šã§ãªããããã¯ã¯åŒã®äœ¿çšæã«èŠä»¶ãæºããããšãã§ããŸãããä»ã®å Žæã§ã¯ç¡å¹ãªåºæ¬åããã£ãŒã«ãåããŸãã¯ãšã€ãªã¢ã¹å®£èšã¯ä¿®æ£ãããŸããã 宣èšåºæã®ä¿®æ£ã«ã€ããŠã¯ã CS9376 ãåç §ããŠãã ããã
å®å šã§ãªãã³ã³ããã¹ããå¿ èŠãšããæäœ
ãã€ã³ãå
ã®ã¡ã¢ãªã«ã¢ã¯ã»ã¹ããæäœã«ã¯ã unsafe ã³ã³ããã¹ããå¿
èŠã§ãã
- ãã€ã³ã¿ãŒéæ¥åç
§ (
*p)ããã€ã³ã¿ãŒ ã¡ã³ã㌠ã¢ã¯ã»ã¹ (p->member)ããã€ã³ã¿ãŒèŠçŽ ã¢ã¯ã»ã¹ (p[i])ã - 颿°ãã€ã³ã¿ãŒã®åŒã³åºãã
- åºå®ãµã€ãº ãããã¡ãŒã§ã®èŠçŽ ã¢ã¯ã»ã¹ã
次ã®äŸã§ã¯ã unsafe ã³ã³ããã¹ãã䜿çšããã«é
åããã³çãããŸããããã€ã³ã¿ãŒã 1 ã€å
ã§éåç
§ããŸãã
public static int ReadValue(int[] numbers)
{
fixed (int* first = numbers)
{
// Dereferencing a pointer accesses unmanaged memory, so it still
// requires an unsafe context.
unsafe
{
return *first;
}
}
}
ç·©ãããªæäœ
æã瀺ãããã¡ã¢ãªã«ã¢ã¯ã»ã¹ããªãæäœã§ã¯ã unsafe ã³ã³ããã¹ããäžèŠã«ãªããŸãã
- ãã€ã³ã¿ãŒåã宣èšãã
&æŒç®åã䜿çšããŠå€æ°ã®ã¢ãã¬ã¹ãååŸããŸãã - 倿°ããã³çããã
fixedã¹ããŒãã¡ã³ãã -
stackallocåŒããã€ã³ã¿ãŒã«å€æããã - ã¢ã³ãããŒãžåã«é©çšããã
sizeofæŒç®åã
次ã®äŸã§ã¯ã unsafe ã³ã³ããã¹ããªãã§ãã€ã³ã¿ãŒãäœæããŠãã³çãããŸãã
public static void CreatePointer()
{
int value = 42;
// Creating a pointer doesn't require an unsafe context.
int* pointer = &value;
int** pointerToPointer = &pointer;
}
public static void PinArray(int[] numbers)
{
// The fixed statement no longer requires an unsafe context.
fixed (int* first = numbers)
{
int* current = first;
}
}
ãããã®ç·©åã¯ãã¢ã»ã³ããªãæŽæ°ãããã¡ã¢ãªå®å
šèŠåã«ãªããã€ã³ãããã©ããã«é¢ä¿ãªãã preview èšèªããŒãžã§ã³ã§ã³ã³ãã€ã«ãããã³ã«é©çšãããŸãã
å®å šã§ãªãåŒ
unsafeåŒunsafe(expression)ã1 ã€ã®åŒãè©äŸ¡ããããã®å®å
šã§ãªãã³ã³ããã¹ããäœæãããŸãã ããã¯ããã£ãŒã«ãåæååãã³ã³ã¹ãã©ã¯ã¿ãŒåæååãcatchå¥ã®whenå¥ãªã©ãunsafe ãããã¯ãæ§æçã«è¡šç€ºã§ããªãå Žåã«äŸ¿å©ã§ãã å®å
šã§ãªãã³ã³ããã¹ãã¯éããã£ãã§çµããã®ã§ãå«ãŸããã¹ããŒãã¡ã³ãã®æ®ãã®éšåã«ã¯æ¡åŒµãããŸããã
次ã®äŸã§ã¯ããã£ãŒã«ãåæåå ( unsafe ãããã¯ãå«ããããšãã§ããªãäœçœ®) å
ã®ãã€ã³ã¿ãŒãéåç
§ããŸãã
// A field initializer can't contain an unsafe block, but it can contain an
// unsafe expression. The unsafe context ends at the closing parenthesis.
public static readonly int Signature = unsafe(ReadSignature());
private static unsafe int ReadSignature()
{
int rawValue = 0x1234;
int* pointer = &rawValue;
return *pointer;
}
unsafeåŒã䜿çšãããšãawaitåŒå
šäœãunsafe ãããã¯ã«ã©ããããã®ã§ã¯ãªããawaitã® 1 ã€ã®ãªãã©ã³ãã«é¢ããå®å
šã§ãªãã³ã³ããã¹ãã®ã¹ã³ãŒããèšå®ããããšãã§ããŸãã
awaitèªäœã¯å®å
šã§ãªãã³ã³ããã¹ãã®å€éšã«ãšã©ãŸããŸããåŸ
æ©äžã®ã¿ã¹ã¯ãçæããåŒã³åºãã ããããã®äžã§å®è¡ãããŸãã
public static async Task<int> ReadSignatureAsync()
{
// The unsafe expression scopes the unsafe context to the call that
// produces the task. The 'await' itself stays outside that context.
return await unsafe(ReadSignatureCoreAsync());
}
private static unsafe Task<int> ReadSignatureCoreAsync()
{
int rawValue = 0x1234;
int* pointer = &rawValue;
return Task.FromResult(*pointer);
}
ä»ã®å®å
šã§ãªãã³ãŒããšåæ§ã«ã unsafe åŒã«ã¯ AllowUnsafeBlocks ã³ã³ãã€ã© ãªãã·ã§ã³ãå¿
èŠã§ããã preview èšèªããŒãžã§ã³ãå¿
èŠã§ãã
æåºã«ã¯å®å šã§ãªã矩åãå¿ èŠ
å¿ é ã®å®å šã§ãªãæäœãåŒã³åºãã¡ã³ããŒã«ã¯ã矩åãäŒéãããããããæåºãããã® 2 ã€ã®éžæè¢ããããŸãã
-
äŒé: ç¬èªã®ã¡ã³ããŒ
unsafeãããŒã¯ããŸãã 矩åã¯åŒã³åºãå ã«æž¡ãããŸãã èªåã§çŸ©åãå®å šã«æ€èšŒã§ããªãå Žåã¯ãäŒéã䜿çšããŸãã -
éé¢: ã¡ã³ããŒã®çœ²åã¯å®å
šãªãŸãŸã«ããŠãããŸãã ã¡ã³ããŒå
ã®çŸ©å (éåžžã¯ã©ã³ã¿ã€ã ã¬ãŒãã䜿çš) ãæ€èšŒããå
éš
unsafeãããã¯ã§å®å šã§ãªãæäœãå®è¡ããŸãã å éšunsafeãããã¯ãå«ãããç¬èªã®çœ²åãããŒã¯ããªãã¡ã³ããŒunsafe㯠å®å šã§ãªãå¢çã§ããå®å šã§ãªãã³ãŒããå®å šã«åŒã³åºãå¯èœãªãµãŒãã§ã¹ã«å€æããŸãã
次ã®ãã¬ãã¥ãŒ ã¢ãã¯ã¢ããã§ã¯ãã¬ãŒãã䜿çšããŠãã®å
¥åãæ€èšŒãããããŒãžãé
åããã³çãããŠããã€ã³ã¿ãŒãèªã¿åããŸãã åŒã³åºãå
㯠unsafe ã³ã³ããã¹ããå¿
èŠãšããŸãããããã¯ãã¡ãœããã矩åãè² ãããã§ãã
// Preview
public static int SumBytes(byte[] source)
{
ArgumentNullException.ThrowIfNull(source);
fixed (byte* first = source)
{
unsafe
{
// SAFETY: the null check and source.Length bound every read to the pinned array.
int total = 0;
for (int i = 0; i < source.Length; i++)
{
total += first[i];
}
return total;
}
}
}
null ãã§ãã¯ãšé
åã®é·ãã¯ãèªã¿åãããããã¡ãŒãè¶ããŠå®è¡ãããå
¥åãé€å€ããããã unsafe ãããã¯å
ã®éåç
§ã¯ãµãŠã³ãã«ãªããŸãã ãã®ã¡ãœããã¯æ®äœçŸ©åãè² ããŸããããã®ãããå®å
šãªåŒã³åºãå¯èœãªçœ²åãå
¬éãããŸãã
å®å šæ§ã«é¢ããããã¥ã¡ã³ã
å¿ é ã®å®å šã§ãªãã¡ã³ããŒã¯ãåŒã³åºãå ãä¿èšŒããå¿ èŠãããå å®¹ãææžåããå¿ èŠããããŸãã æŽæ°ãããã¢ãã«ã§ã¯ã次㮠2 ã€ã®è£å®çãªã³ã¡ã³ã ã¹ã¿ã€ã«ãæšå¥šãããŸãã
- 眲åã®äžã«ãã
/// <safety>ããã¥ã¡ã³ã ãããã¯ã«ã¯ãæ£åŒãªã³ã³ãã©ã¯ã (åŒã³åºãå ãæºããå¿ èŠãããæ¡ä»¶) ãèšèŒãããŠããŸãã ã¢ãã©ã€ã¶ãŒã¯ãäžè¶³ããŠãã å¿ é ã®å®å šã§ãªã ã¡ã³ããŒã«ãã©ã°ãèšå®ã§ããŸãã -
// SAFETY:ãããã¯å ã®unsafeã³ã¡ã³ãã¯ãæ¬æãèªãéçºè ãšç£æ»è ã®ããã«ããã®å Žæã§æäœã鳎ãçç±ãèšé²ããŸãã
次ã®ãã¬ãã¥ãŒã®äŸã¯ã requires-unsafeReadByte ã¡ãœããã®äž¡æ¹ã®ã¹ã¿ã€ã«ã瀺ããŠããŸãã
// Preview
/// <summary>Reads a single byte from unmanaged memory.</summary>
/// <safety>
/// The sum of <paramref name="ptr"/> and <paramref name="offset"/> must address a byte
/// the caller is permitted to read.
/// </safety>
public static unsafe byte ReadByte(IntPtr ptr, int offset)
{
byte* address = (byte*)ptr;
unsafe
{
// SAFETY: relies on the caller obligation stated in the <safety> block.
return address[offset];
}
}
/// <safety> ãããã¯ã«ãã£ãŠã³ã³ãã©ã¯ããéç¥ãããŸãã ã³ã³ãã©ã¯ãã¯ããã¹ãŠã®åŒã³åºãå
ãšã¬ãã¥ãŒæ
åœè
ãåç
§ããããã¥ã¡ã³ãã«å±ããŸãã
å®å šã§ãªããã£ãŒã«ã
ãã£ãŒã«ãã® unsafe 修食åã¯ã宣èšãããåããå€åŽã®åãä¿æããä»ã®ã³ãŒããäŸåããã³ã³ãã©ã¯ãã衚ããŠããªãå Žåã«äœ¿çšããŸãã å®å
šã§ãªãã®ã¯ãåã·ã¹ãã ãèŠããã®ãšåãçŽæãããã®ã®éã®ã®ã£ããã«ååšããŸãã ãã®ä¿®é£Ÿåã¯ããã£ãŒã«ããžã®ãã¹ãŠã®æžã蟌ã¿ã unsafe ãããã¯ã«åŒ·å¶ããæžã蟌ã¿ã 1 ãæã§ç¢ºèªã§ããããã«ããŸãã
æãæç¢ºãªã±ãŒã¹ã¯ããã€ãã£ã ãã€ã³ã¿ãŒãä¿æãããã£ãŒã«ãã§ãã ãã€ã³ã¿ãŒã¯ã System.Span<T> ãšåãããã«ã¢ãã¬ã¹æå®ãããã€ãæ°ã宣èšããªããããæ ŒçŽåã¯ãã®æ å ±èªäœãä¿æããŸãã
// Preview
public class NativeBuffer
{
/// <safety>
/// Null, or points to a buffer of Length bytes.
/// </safety>
private unsafe byte* _pointer;
public int Length { get; }
public byte ReadAt(int index)
{
ArgumentOutOfRangeException.ThrowIfNegative(index);
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Length);
unsafe
{
// SAFETY: the bounds checks confine the read to the buffer that _pointer addresses.
return _pointer[index];
}
}
}
readonly unsafe ãã£ãŒã«ãã¯ãã³ã³ãã©ã¯ããšçµã¿èŸŒã¿ã®ã¬ãŒããçµã¿åãããŠããŸããunsafeã€ã³ããªã¢ã³ãã«ååãä»ããŸããreadonlyãæ§ç¯åŸã«æžã蟌ã¿ãäžæãããã®ãé²ããŸãã ããããã£ãŸãã¯ã€ãã³ã unsafe ãããŒã¯ããŠãããããã³ã° ãã£ãŒã«ãã« å®å
šã§ã¯ãªãå¿
èŠã¯ãããŸããã
æŽæ°ãããã«ãŒã«ã®äžã§ãåå
ã®ãã¹ãŠã®ã€ã³ã¹ã¿ã³ã¹ ãã£ãŒã«ããã safe ãŸã㯠unsafeã®æç€ºçãŸãã¯æ¡åŒµã¬ã€ã¢ãŠãã§ããŒã¯ããŸãã ãããã®åã¯ãLayoutKind.Explicitã«èšå®StructLayoutAttributeããŸãã¯ExtendedLayoutAttributeã§ããŒã¯ãããŸãã 0 以å€ã® StructLayoutAttribute.Pack ãŸã㯠StructLayoutAttribute.Sizeãæã€åã®ã€ã³ã¹ã¿ã³ã¹ ãã£ãŒã«ãã«åã修食åãé©çšããŸã (ã·ãŒã±ã³ã·ã£ã«ãŸãã¯èªåã¬ã€ã¢ãŠãã®å Žåã§ã)ã æå®ãããŠããªãå€ãŸãã¯ãŒãã®å€ã¯ãããèªäœã§è¿œå ã®èŠä»¶ãããªã¬ãŒããŸããã éçãã£ãŒã«ããšå®æ°ãã£ãŒã«ãã¯é€å€ãããŸãã åæããããããã³ã° ãã£ãŒã«ãã®ææããããã£ãŸãã¯ã€ãã³ãã«æ³šéãä»ããŸãã
æé»çã«çæãããã¹ãã¬ãŒãžã®èšºæãšä¿®æ£ã«ã€ããŠã¯ãã CS9392: ãã£ãŒã«ã ã¬ã€ã¢ãŠãã®å®å šæ§ããåç §ããŠãã ããã
safe ããŒã¯ãŒã
æŽæ°ãããã¢ãã«ã§ã¯ã宣èšã蚌æãã safe ã³ã³ããã¹ã ããŒã¯ãŒãã远å ãããŸããããã¯ãã³ã³ãã€ã©ãéžæãæç€ºçã«è¡ãå¿
èŠãããå Žåã«æ£ãããã©ããã蚌æããŸãã
éåžžã®å®£èšã¯æ¢å®ã§å®å
šã§ããããã safe 修食åã¯å¿
èŠãããŸããã
unsafeã³ãŒãã¯ãŸãã§ãããããã»ãšãã©ã®ã³ãŒãããŒã¹ã§ã¯ãæ¢å®å€ãå®å
šã§ãªãå Žåãã³ã³ãã€ã©ãæç€ºçãªéžæãå¿
èŠãšããå Žåã«ã®ã¿ãsafeã䜿çšããŸãã ãã®ä¿®é£Ÿåã¯ã宣èšãå¿
é ã§ãªãå®å
šã§ãªããã®ãšããŠããŒã¯ããŸããå®å
šãªåå¥ã³ã³ããã¹ãã確ç«ããããå²ãŸããŠããå®å
šã§ãªãã³ã³ããã¹ããåãæ¶ãããããããšã¯ãããŸããã åã宣èšã§ safe ãš unsafe ãçµã¿åãããããšã¯ã§ããŸããã æ°ããã³ã³ãã€ã©ã§ã¯ã unsafe 宣èšä¿®é£Ÿåãš safe 宣èšä¿®é£Ÿåã®äž¡æ¹ã«ãæŽæ°ãããèŠåã®é©çšãªããã€ã³ãšã¯å¥ã« AllowUnsafeBlocks ãªãã·ã§ã³ãå¿
èŠã§ãã ãããæå®ããªãå Žåã宣èšä¿®é£Ÿå㯠CS9401 ãçæããå®å
šã§ãªããããã¯ã§ã¯ CS0227 ãçæããç¶ããŸãã Roslyn ã¯ã.NET 11.0.100 以éãVisual Studio 2026 ããŒãžã§ã³ 18.13 ã§å°å
¥ããã修食åãã§ãã¯ãææžåããŸãã .NET 11 ã³ã³ãã€ã©ã¯ãsafeã«ãã®ãªãã·ã§ã³ãå¿
èŠãšãããunsafe宣èšä¿®é£Ÿåã« CS0227 ã䜿çšããŸãã 詳现ã«ã€ããŠã¯ã å®å
šã§ãªãã³ã³ããã¹ãã®èŠä»¶ ã«é¢ããããŒãžãåç
§ããŠãã ããã ã¡ã¢ãª ã»ãŒã ã¢ãã«èªäœã¯ãã¬ãã¥ãŒæ©èœã®ãŸãŸã§ãã
extern ã¡ã³ããŒã¯ãã€ãã£ã ã³ãŒããåŒã³åºãã®ã§ãã³ã³ãã€ã©ã¯ãã®å®å
šæ§ãåé¡ã§ããŸããã æŽæ°ãããã¢ãã«ã§ã¯ãexternãŸãã¯LibraryImportã®ããããã®éšåã¡ãœããsafeå«ãããã¹ãŠã®unsafe宣èšãããŒã¯ããŸãã
// Preview
[LibraryImport("libc")]
internal static safe partial int getpid();
[LibraryImport("libc", StringMarshalling = StringMarshalling.Utf8)]
internal static unsafe partial nint strlen(byte* str);
getpid ã¯ãã©ã¡ãŒã¿ãŒãåãåãããããªããã£ããè¿ãã®ã§ãäœæè
ã¯åŒã³åºããå®å
šã§ããããšã蚌æããåŒã³åºãå
ã¯åŒãªãã§ããã䜿çšããŸãã
strlen ã¯ãã€ãã£ã ã³ãŒããéåç
§ããçãã€ã³ã¿ãŒãåãåãã®ã§ã宣èšã¯ unsafe ãããåŒã³åºãå
ã«çŸ©åãäŒéãããŸãã äž¡æ¹ã®ä¿®é£Ÿåãçç¥ãããšãšã©ãŒãçºçãããããå®å
šäžã®å€æã匷å¶ãããŸãã æç€ºçãŸãã¯æ¡åŒµã¬ã€ã¢ãŠãã®åã®ãã£ãŒã«ãã§ã¯ãåãèŠåã䜿çšãããŸãã
C# èšèªä»æ§
詳现ã«ã€ããŠã¯ãC# èšèªä»æ§ã®å®å šã§ãªãã³ãŒãã®ç« ãåç §ããŠãã ããã
æŽæ°ãããã¡ã¢ãªå®å šã¢ãã«ã®èšèšã«ã€ããŠã¯ã ã¡ã¢ãªå®å šæ©èœã®ä»æ§ãåç §ããŠãã ããã