
æè¿ãnullå¯èœãªåç §ã¿ã€ãã話é¡ã«ãªã£ãŠããŸãããã ããå€ãè¯ãnullå¯èœå€ã¿ã€ãã¯ãªããªã£ãŠããããçŸåšãç©æ¥µçã«äœ¿çšãããŠããŸãã圌ããšäžç·ã«åãããšã®ãã¥ã¢ã³ã¹ãããèŠããŠããŸããïŒãã®èšäºãèªãã§ãç¥èãæŽæ°ãŸãã¯ãã¹ãããããšããå§ãããŸãããµã³ãã«ã®CïŒããã³ILã³ãŒããCLI仿§ãžã®åç §ãããã³CoreCLRã³ãŒããå«ãŸããŠããŸããç§ã¯è峿·±ãåé¡ããå§ããããšãææ¡ããŸãã
泚ããã«å¯èœåç §ã¿ã€ãã«èå³ãããå Žåã¯ãç§ã®ååã®èšäºã®ããã€ãããã§ãã¯ããŠãã ããïŒãCïŒ8.0ããã³éçåæã®ãã«å¯èœåç §ã¿ã€ãããããã«å¯èœåç §ã¯ä¿è·ããªãããããŠããã«èšŒæããããŸããã
以äžã®ãµã³ãã«ã³ãŒããèŠãŠãã³ã³ãœãŒã«ã«åºåãããå 容ã«çããŠãã ããããããŠãåãããã«éèŠãªã®ã¯ããã®çç±ã§ããã³ã³ãã€ã©ã®ãã³ããããã¥ã¡ã³ããæç®ã®é²èЧãªã©ãè¡ããã«ããã®ãŸãŸåçããããšã«ããã«åæããŸãããã :)
static void NullableTest()
{
int? a = null;
object aObj = a;
int? b = new int?();
object bObj = b;
Console.WriteLine(Object.ReferenceEquals(aObj, bObj)); // True or False?
}

ããŠãå°ãèããŠã¿ãŸããããç§ã«ã¯ãèµ·ããåŸããšæãããããã€ãã®äž»èŠãªèãæ¹ãèããŠã¿ãŸãããã
1. intïŒ -åç §ã¿ã€ãã
ãã®ããã«æšè«ããŸããããintãšã¯äœã§ããïŒåç §ã¿ã€ãã§ãããã®å Žåãå€ãæžã蟌ãŸãããã«ãããã¯ãŸãèšé²ãããAOBJå²ãåœãŠåŸããããªããžã§ã¯ããžã®åç §ã¯bã«æžã蟌ãŸããŸãããŸããå²ãåœãŠåŸã«bObjã«æžã蟌ãŸããŸãããã®çµæãObject.ReferenceEqualsã¯nullãšnull以å€ã®ãªããžã§ã¯ãåç §ãåŒæ°ãšããŠåãåãããã...åœç¶ã®ããšãªãããçãã¯Falseã§ãã
2. intïŒ -éèŠãªã¿ã€ãã
ãŸãã¯å€åããªãã¯ãã®intãçãïŒåç §ã¿ã€ãã§ããïŒãããŠãintåŒã«ããããããããã確信ããŠããŸããïŒ a = nullïŒããŠãå察åŽããè¡ã£ãŠãintãšã¯äœãããå§ããŸãããã -éèŠãªã¿ã€ãã
ãã®å ŽåãåŒintïŒ a = nullã¯å°ãå¥åŠã«èŠããŸãããCïŒã§åã³ç ç³ãäžã«æ³šããããšä»®å®ããŸããããçš®ã®ãªããžã§ã¯ããæ ŒçŽããŠããããšãããããŸãããbã¯ããçš®ã®ãªããžã§ã¯ããæ ŒçŽããŸãã倿°aObjããã³bObjãåæåãããšãaããã³bã«æ ŒçŽãããŠãããªããžã§ã¯ããããã¯ãããŸããããã®çµæãaObjãšbObjã«ç°ãªãåç §ãæžã蟌ãŸããŸããObject.ReferenceEqualsã¯ãããŸããŸãªãªããžã§ã¯ããžã®åç §ãåŒæ°ãšããŠåãããšã倿ããŸããããããã£ãŠã...
ãã¹ãŠãæçœã§ãããçãã¯Falseã§ãã
3.ããã§ã¯Nullable <T>ã䜿çšãããŠãããšä»®å®ããŸãã
äžèšã®ãªãã·ã§ã³ãæ°ã«å ¥ããªãã£ããšããŸããããããªãã¯intããªãããšãå®å šã«ããç¥ã£ãŠããã®ã§ïŒå®éã«ã¯ããã§ã¯ãããŸããããå€ã®ã¿ã€ãã¯Nullable <T>ã§ããããã®å Žåã¯Nullable <int>ã䜿çšãããŸãããŸããå®éã«ã¯aãšbã§ãããçè§£ããŠããŸãåäžã®ãªããžã§ã¯ãããããŸããåæã«ãaObjãšbObjã«å€ãæžã蟌ããšãã«ãããã³ã°ãçºçãããã®çµæãç°ãªããªããžã§ã¯ããžã®åç §ãååŸãããããšãå¿ããªãã§ãã ãããObject.ReferenceEqualsã¯ããŸããŸãªãªããžã§ã¯ããžã®åç §ãåãå ¥ããããã...
åœç¶ã®ããšãªãããçãã¯Falseã§ãã
4ã;ïŒ
å€ã®çš®é¡ããå§ãã人ã®ããã«-åç §ã®æ¯èŒã«ã€ããŠçªç¶çåãããå Žåã¯ãdocs.microsoft.comã§Object.ReferenceEqualsã®ããã¥ã¡ã³ããåç §ããŠãã ããã..ãç¹ã«ãå€ã®ã¿ã€ããšããã¯ã¹å/ããã¯ã¹åè§£é€ã®ãããã¯ã«ãè§ŠããŠããŸãã確ãã«ãéèŠãªã¿ã€ãã®ã€ã³ã¹ã¿ã³ã¹ãã¡ãœããã«çŽæ¥æž¡ãããããã±ãŒãžãåå¥ã«åãåºããå Žåã説æããŠããŸãããæ¬è³ªã¯åãã§ãã
å€ã®ã¿ã€ããæ¯èŒããå ŽåãobjAãšobjBãå€ã¿ã€ãã®å ŽåãReferenceEqualsã¡ãœããã«æž¡ãããåã«ããã¯ã¹åãããŸããããã¯ãobjAãšobjBã®äž¡æ¹ãå€ã¿ã€ãã®åãã€ã³ã¹ã¿ã³ã¹ã衚ãå Žåã§ããæ¬¡ã®äŸã«ç€ºãããã«ãReferenceEqualsã¡ãœããã¯falseãè¿ãããšãæå³ããŸãã
ããã§èšäºã宿ãããããšãã§ããããã«æãããŸãããæ£è§£ã¯Trueã§ãã
ããŠããããçè§£ããŸãããã
çè§£
ã·ã³ãã«ãšé¢çœãã®2ã€ã®æ¹æ³ããããŸãã
ç°¡åãªæ¹æ³
intïŒããã®Nullable <intå>ãNullable <T>ããã¥ã¡ã³ããéããŸããããã§ã¯ãããã¯ã·ã³ã°ãšã¢ã³ãã¯ã·ã³ã°ãã»ã¯ã·ã§ã³ã確èªããŸããååãšããŠãããã ãã§ã-åäœã¯ããã§èª¬æãããŠããŸãããããã詳现ãå¿ èŠãªå Žåã¯ãè峿·±ãæ¹æ³ã§ãæåŸ ããŸãã;ïŒ
é¢çœãæ¹æ³
ãã®ãã¹ã«é¢ããååãªããã¥ã¡ã³ãã¯ãããŸããã圌女ã¯ãã®æ¯ãèãã«ã€ããŠèª¬æããŸãããããªãããšãã質åã«ã¯çããŸããã
å®éã«ã¯intãšã¯äœã§ããïŒãããŠãã«é©åãªæèã§ïŒãªããã®ããã«æ©èœããã®ã§ããïŒILã³ãŒãã¯ç°ãªãã³ãã³ãã䜿çšããŸããïŒCLRã¬ãã«ã§ã®åäœã¯ç°ãªããŸããïŒä»ã®éæ³ã¯ãããŸããïŒint
ãšã³ãã£ãã£ãè§£æããããšããå§ããŸãããïŒåºæ¬ãèŠããŠãåŸã ã«å ã®ã±ãŒã¹ã®åæã«åãæãããŸããCïŒã¯ããªããççŸãªãèšèªã§ããããã宿çã«ILã³ãŒããåç §ããŠãç©äºã®æ¬è³ªã調ã¹ãŸãïŒã¯ããCïŒã®ããã¥ã¡ã³ãã¯ä»æ¥ã®ç§ãã¡ã®ããæ¹ã§ã¯ãããŸããïŒã
intïŒãNullable <T>
ããã§ã¯ãååãšããŠnullå¯èœãªå€ã¿ã€ãã®åºæ¬ïŒããããäœã§ããããILã§äœã«ã³ã³ãã€ã«ãããããªã©ïŒãèŠãŠãããŸãã課é¡ããã®è³ªåãžã®åçã«ã€ããŠã¯ã次ã®ã»ã¯ã·ã§ã³ã§èª¬æããŸãã
ã³ãŒãã®äžéšãèŠãŠã¿ãŸãããã
int? aVal = null;
int? bVal = new int?();
Nullable<int> cVal = null;
Nullable<int> dVal = new Nullable<int>();
ãããã®å€æ°ã®åæåã¯CïŒã§ã¯ç°ãªã£ãŠèŠããŸããããã¹ãŠã®å€æ°ã«å¯ŸããŠåãILã³ãŒããçæãããŸãã
.locals init (valuetype [System.Runtime]System.Nullable`1<int32> V_0,
valuetype [System.Runtime]System.Nullable`1<int32> V_1,
valuetype [System.Runtime]System.Nullable`1<int32> V_2,
valuetype [System.Runtime]System.Nullable`1<int32> V_3)
// aVal
ldloca.s V_0
initobj valuetype [System.Runtime]System.Nullable`1<int32>
// bVal
ldloca.s V_1
initobj valuetype [System.Runtime]System.Nullable`1<int32>
// cVal
ldloca.s V_2
initobj valuetype [System.Runtime]System.Nullable`1<int32>
// dVal
ldloca.s V_3
initobj valuetype [System.Runtime]System.Nullable`1<int32>
ã芧ã®ãšãããCïŒã§ã¯ããã¹ãŠã«å¿èããã®æ§æäžã®ç ç³ãæ¯ããããããŠãããããå®éãããªããšç§ã¯ããè¯ãçããŠããŸãã
- intïŒ-éèŠãªã¿ã€ãã
- intïŒ-Nullable <int>ãšåãã§ããILã³ãŒãã¯Nullable <int32>ã§æ©èœããŠããŸãã
- intïŒaVal = nullã¯ãNullable <int> ãšåãã§ããaVal= new Nullable <int>ïŒïŒãILã§ã¯ãããã¯initobjã¹ããŒãã¡ã³ãã«å±éãããããŒããããã¢ãã¬ã¹ã§ããã©ã«ãã®åæåãå®è¡ããŸãã
次ã®ã³ãŒãã«ã€ããŠèããŠã¿ãŸãã
int? aVal = 62;
ããã©ã«ãã®åæåãçè§£ããŸãã-äžèšã®å¯Ÿå¿ããILã³ãŒããèŠãŸãããaValã62ã«åæåããå Žåãããã§äœãèµ·ãããŸããïŒ
ILã³ãŒããèŠãŠã¿ãŸãããã
.locals init (valuetype [System.Runtime]System.Nullable`1<int32> V_0)
ldloca.s V_1
ldc.i4.s 62
call instance void valuetype
[System.Runtime]System.Nullable`1<int32>::.ctor(!0)
ç¹°ãè¿ããŸãããè€éãªããšã¯äœããããŸãããã¢ãã¬ã¹aValãè©äŸ¡ã¹ã¿ãã¯ãšå€62ã«ããŒãããããã®åŸãNullable <T>ïŒTïŒçœ²åãæã€ã³ã³ã¹ãã©ã¯ã¿ãŒãåŒã³åºãããŸããã€ãŸããæ¬¡ã®2ã€ã®åŒã¯å®å šã«åäžã«ãªããŸãã
int? aVal = 62;
Nullable<int> bVal = new Nullable<int>(62);
ILã³ãŒããããäžåºŠèŠããšãåãããšãããããŸãã
// int? aVal;
// Nullable<int> bVal;
.locals init (valuetype [System.Runtime]System.Nullable`1<int32> V_0,
valuetype [System.Runtime]System.Nullable`1<int32> V_1)
// aVal = 62
ldloca.s V_0
ldc.i4.s 62
call instance void valuetype
[System.Runtime]System.Nullable`1<int32>::.ctor(!0)
// bVal = new Nullable<int>(62)
ldloca.s V_1
ldc.i4.s 62
call instance void valuetype
[System.Runtime]System.Nullable`1<int32>::.ctor(!0)
æ€æ»ã¯ã©ãã§ããïŒããšãã°ã次ã®ã³ãŒãã¯å®éã«ã¯ã©ã®ããã«èŠããŸããïŒ
bool IsDefault(int? value) => value == null;
ããã§ããçè§£ã®ããã«ã察å¿ããILã³ãŒãã«ããäžåºŠç®ãåããŸãããã
.method private hidebysig instance bool
IsDefault(valuetype [System.Runtime]System.Nullable`1<int32> 'value')
cil managed
{
.maxstack 8
ldarga.s 'value'
call instance bool valuetype
[System.Runtime]System.Nullable`1<int32>::get_HasValue()
ldc.i4.0
ceq
ret
}
ãæ³åã®ãšãããå®éã«ã¯nullã¯ãããŸãããçºçããã®ã¯Nullable <T> .HasValueããããã£ã®åŒã³åºãã ãã§ããã€ãŸããCïŒã®åãããžãã¯ã¯ã次ã®ããã«äœ¿çšããããšã³ãã£ãã£ã«é¢ããŠããæç€ºçã«èšè¿°ã§ããŸãã
bool IsDefaultVerbose(Nullable<int> value) => !value.HasValue;
ILã³ãŒãïŒ
.method private hidebysig instance bool
IsDefaultVerbose(valuetype [System.Runtime]System.Nullable`1<int32> 'value')
cil managed
{
.maxstack 8
ldarga.s 'value'
call instance bool valuetype
[System.Runtime]System.Nullable`1<int32>::get_HasValue()
ldc.i4.0
ceq
ret
}
èŠçŽããŸãããïŒ
- Nullableå€ã¿ã€ãã¯ãNullable <T>ã¿ã€ããç ç²ã«ããŠå®è£ ãããŸãã
- intïŒ-å®éã«ã¯ãæ±çšå€ã¿ã€ãNullable <T>ã®æ§ç¯ãããã¿ã€ãã
- intïŒa = null-ããã©ã«ãå€ã䜿çšããNullable <int>ã¿ã€ãã®ãªããžã§ã¯ãã®åæåãå®éã«ã¯ããã«ã¯nullã¯ãããŸããã
- ifïŒa == nullïŒ -ç¹°ãè¿ããŸãããnullã¯ãªããNullable <T> .HasValueããããã£ãžã®åŒã³åºãããããŸãã
Nullable <T>ã¿ã€ã ã®ãœãŒã¹ã³ãŒãã¯ãããšãã°ãdotnet /ã©ã³ã¿ã€ã ãªããžããªã®GitHubïŒãœãŒã¹ã³ãŒããã¡ã€ã«ãžã®çŽæ¥ãªã³ã¯ïŒã§è¡šç€ºã§ããŸããããã«ã¯ã³ãŒããããŸããªãã®ã§ãèå³ãåŒãããã«äžèªããããšããå§ãããŸãããããããæ¬¡ã®äºå®ãåŠã¶ïŒãŸãã¯èŠããïŒããšãã§ããŸãã
䟿å®äžãNullable <T>ã¿ã€ãã¯ä»¥äžãå®çŸ©ããŸãã
- TããNullable <T>ãžã®æé»ã®å€ææŒç®å;
- Nullable <T>ããTãžã®æç€ºçãªå€ææŒç®åã
äœæ¥ã®äž»ãªããžãã¯ã¯ã2ã€ã®ãã£ãŒã«ãïŒããã³å¯Ÿå¿ããããããã£ïŒãä»ããŠå®è£ ãããŸãã
- Tå€-Nullable <T>ã§ã©ãããããå€èªäœã
- bool hasValueã¯ãã©ãããŒã«å€ãå«ãŸããŠãããã©ããã瀺ããã©ã°ã§ããåŒçšç¬Šã§å²ãŸããŠããå Žåãå®éã«ã¯Nullable <T>ã«ã¯åžžã«ã¿ã€ãTã®å€ãå«ãŸããŸãã
nullå¯èœãªå€ã®ã¿ã€ãã«ã€ããŠåŸ©ç¿ããã®ã§ãããã±ãŒãžã®ç¶æ ãèŠãŠã¿ãŸãããã
ãã«å¯èœãª<T>ãããã³ã°
å€ã¿ã€ãã®ãªããžã§ã¯ããããã¯ãããšãããŒãäžã«æ°ãããªããžã§ã¯ããäœæãããããšãæãåºããŠãã ãããæ¬¡ã®ã³ãŒãã¹ããããã¯ããã®åäœã瀺ããŠããŸãã
int aVal = 62;
object obj1 = aVal;
object obj2 = aVal;
Console.WriteLine(Object.ReferenceEquals(obj1, obj2));
2ã€ã®ãã¯ã·ã³ã°æäœãçºçãã2ã€ã®ãªããžã§ã¯ããäœæããããã®åç §ãobj1ãšobj2ã«æžã蟌ãŸãããããåç §ã æ¯èŒããçµæã¯falseã§ãããšäºæ³ãããŸãã ããã§ãintãNullable <int>ã«å€æŽããŸãã
Nullable<int> aVal = 62;
object obj1 = aVal;
object obj2 = aVal;
Console.WriteLine(Object.ReferenceEquals(obj1, obj2));
çµæã¯ãŸã æåŸ ãããŠããŸã-falseã
ãããŠä»ã62ã®ä»£ããã«ããã©ã«ãå€ãæžããŸãã
Nullable<int> aVal = new Nullable<int>();
object obj1 = aVal;
object obj2 = aVal;
Console.WriteLine(Object.ReferenceEquals(obj1, obj2));
Iii ...çµæã¯çªç¶çã«ãªããŸãã2ã€ã®ãªããžã§ã¯ããäœæãã2ã€ã®ç°ãªããªããžã§ã¯ãã«ãªã³ã¯ããããã¹ãŠåã2ã€ã®ãããã³ã°æäœãããããã«èŠããŸãããçµæã¯æ£ããã§ãã
ãããããã¯ããããåã³ç ç³ã§ãããILã³ãŒãã¬ãã«ã§äœãã倿ŽãããŸããïŒã©ãã©ãã
äŸN1ã
CïŒã³ãŒãïŒ
int aVal = 62;
object aObj = aVal;
ILã³ãŒãïŒ
.locals init (int32 V_0,
object V_1)
// aVal = 62
ldc.i4.s 62
stloc.0
// aVal
ldloc.0
box [System.Runtime]System.Int32
// aObj
stloc.1
äŸN2ã
CïŒã³ãŒãïŒ
Nullable<int> aVal = 62;
object aObj = aVal;
ILã³ãŒãïŒ
.locals init (valuetype [System.Runtime]System.Nullable`1<int32> V_0,
object V_1)
// aVal = new Nullablt<int>(62)
ldloca.s V_0
ldc.i4.s 62
call instance void
valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0)
// aVal
ldloc.0
box valuetype [System.Runtime]System.Nullable`1<int32>
// aObj
stloc.1
äŸN3ã
CïŒã³ãŒãïŒ
Nullable<int> aVal = new Nullable<int>();
object aObj = aVal;
ILã³ãŒãïŒ
.locals init (valuetype [System.Runtime]System.Nullable`1<int32> V_0,
object V_1)
// aVal = new Nullable<int>()
ldloca.s V_0
initobj valuetype [System.Runtime]System.Nullable`1<int32>
// aVal
ldloc.0
box valuetype [System.Runtime]System.Nullable`1<int32>
// aObj
stloc.1
ã芧ã®ãšããããããã³ã°ã¯ã©ãã§ãåãæ¹æ³ã§è¡ãããŸã-ããŒã«ã«å€æ°ã®å€ãè©äŸ¡ã¹ã¿ãã¯ã«ããŒãããïŒldlocåœä»€ïŒããã®åŸãboxã³ãã³ããåŒã³åºãããšã«ãã£ãŠãããã³ã°èªäœãå®è¡ãããã©ã®ã¿ã€ãããããã³ã°ãããã瀺ãããŸãã
ç§ãã¡ã¯ãã«å€ããå ±éèšèªåºç€ã®ä»æ§ã®èšè¿°ãèŠããã¯ã¹ã®ã³ãã³ãããã³NULLå¯èœãªã¿ã€ãã«ã€ããŠã®è峿·±ãããŒããèŠã€ããïŒ
typeTokãå€åã®å Žåãç®±ã®åœä»€å€æã¯ããã®ç®±å ¥ããã©ãŒã ã«VAL ...ãnullå¯èœãªã¿ã€ãã®å Žåãããã¯valã®HasValueããããã£ãæ€æ»ããããšã«ãã£ãŠè¡ãããŸããfalseã®å Žåãnullåç §ãã¹ã¿ãã¯ã«ããã·ã¥ãããŸãããã以å€ã®å Žåããã¯ã·ã³ã°valã®Valueããããã£ã®çµæã¯ã¹ã¿ãã¯ã«ããã·ã¥ãããŸãã
ããããããiãã«ç¹åšããããã€ãã®çµè«ããããŸãã
- Nullable <T>ãªããžã§ã¯ãã®ç¶æ ãèæ ®ãããŸãïŒåã«æ€èšããHasValueãã©ã°ããã§ãã¯ãããŸãïŒãå Žåã®Nullable <T>ã¯ïŒå€ãå«ãŸããŠããªãhasValueã¯ã§ããåœïŒãããã¯ã¹ãã«ãªããŸããã«ã
- å ŽåNULLå¯èœ<T>ã¯å€ãå«ãïŒhasValueã¯-çã®ïŒã次ãã§å è£ ç®çã§ã¯ãªãã®Nullable <T> ãã®ã€ã³ã¹ã¿ã³ã¹Tã«æ ŒçŽãããå€ã®ã¿ã€ãã®Nullable <T> ã
- ãããã³ã°ãåŠçããããã®ç¹å®ã®ããžãã¯Nullable <T>ã¯ãCïŒã¬ãã«ã§ã¯å®è£ ãããŠããããILã¬ãã«ã§ãå®è£ ãããŠããŸãããCLRã«å®è£ ãããŠããŸãã
äžã§èª¬æ ããNullable <T>ã®äŸã«æ»ããŸãããã
æåïŒ
Nullable<int> aVal = 62;
object obj1 = aVal;
object obj2 = aVal;
Console.WriteLine(Object.ReferenceEquals(obj1, obj2));
梱å åã®ã¢ã€ãã ã®ç¶æ ïŒ
- T- > int ;
- å€-> 62 ;
- hasValue- > trueã
å€62ã¯2åããã¯ããïŒãã®å Žåãintã¿ã€ãã®ã€ã³ã¹ã¿ã³ã¹ãããã¯ãããNullable <int>ã§ã¯ãªãããšã«æ³šæããŠãã ããïŒã2ã€ã®æ°ãããªããžã§ã¯ããäœæãããç°ãªããªããžã§ã¯ããžã®2ã€ã®åç §ãååŸããããã®çµæã¯falseã§ãã
2çªç®ïŒ
Nullable<int> aVal = new Nullable<int>();
object obj1 = aVal;
object obj2 = aVal;
Console.WriteLine(Object.ReferenceEquals(obj1, obj2));
梱å åã®ã¢ã€ãã ã®ç¶æ ïŒ
- T- > int ;
- value- > defaultïŒãã®å Žåã0ã¯intã®ããã©ã«ãå€ã§ãïŒ;
- hasValue- > falseã
以æ¥hasValueã¯ã§ããåœã®ãäœã®ãªããžã§ã¯ãã¯ããŒãäžã«äœæãããŠããªãããšãã¯ã·ã³ã°ã®åäœãè¿ããŸããã«ã«æžã蟌ãŸããOBJ1ããã³OBJ2ãäºæ³ã©ããããããã®å€ãæ¯èŒãããšãtrueãåŸãããŸãã
èšäºã®åé ã«ãã£ãå ã®äŸã§ã¯ããŸã£ããåãããšãèµ·ãããŸãã
static void NullableTest()
{
int? a = null; // default value of Nullable<int>
object aObj = a; // null
int? b = new int?(); // default value of Nullable<int>
object bObj = b; // null
Console.WriteLine(Object.ReferenceEquals(aObj, bObj)); // null == null
}
楜ãã¿ã®ããã«ãåè¿°ã®dotnet /ã©ã³ã¿ã€ã ãªããžããªããã®CoreCLRãœãŒã¹ã³ãŒããèŠãŠã¿ãŸããããobject.cppãã¡ã€ã«ãå ·äœçã«ã¯ãå¿ èŠãªããžãã¯ãå«ãNullable :: Boxã¡ãœããã«é¢å¿ããããŸãã
OBJECTREF Nullable::Box(void* srcPtr, MethodTable* nullableMT)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_COOPERATIVE;
}
CONTRACTL_END;
FAULT_NOT_FATAL(); // FIX_NOW: why do we need this?
Nullable* src = (Nullable*) srcPtr;
_ASSERTE(IsNullableType(nullableMT));
// We better have a concrete instantiation,
// or our field offset asserts are not useful
_ASSERTE(!nullableMT->ContainsGenericVariables());
if (!*src->HasValueAddr(nullableMT))
return NULL;
OBJECTREF obj = 0;
GCPROTECT_BEGININTERIOR (src);
MethodTable* argMT = nullableMT->GetInstantiation()[0].AsMethodTable();
obj = argMT->Allocate();
CopyValueClass(obj->UnBox(), src->ValueAddr(nullableMT), argMT);
GCPROTECT_END ();
return obj;
}
ãããç§ãã¡ãäžã§è©±ãããã¹ãŠã§ããå€ãä¿åããªãå ŽåãNULLãè¿ããŸãïŒ
if (!*src->HasValueAddr(nullableMT))
return NULL;
ãã以å€ã®å Žåã¯ãããã±ãŒãžãäœæããŸãã
OBJECTREF obj = 0;
GCPROTECT_BEGININTERIOR (src);
MethodTable* argMT = nullableMT->GetInstantiation()[0].AsMethodTable();
obj = argMT->Allocate();
CopyValueClass(obj->UnBox(), src->ValueAddr(nullableMT), argMT);
çµè«
èå³ãåŒãããã«ãèšäºã®æåããååãå人ã«äŸã瀺ãããšãææ¡ããŸãã圌ãã¯æ£ããçããåºãããããå®èšŒããããšãã§ããã§ããããïŒããã§ãªãå Žåã¯ãèšäºãèªãããã«æåŸ ããŠãã ããã圌ããã§ãããªã-ãŸããç§ã®å°æ¬ïŒ
å°ããããã©æ¥œããåéºã ã£ããšæããŸãã:)
PS誰ãã質åããããããããŸããïŒãã®ãããã¯ãžã®æ²¡é ã¯ã©ã®ããã«å§ãŸã£ãã®ã§ããïŒObject.ReferenceEqualsãåŒæ°ã§æ©èœãããã®ãã¡ã®1ã€ãéèŠãªåã§è¡šããããšããäºå®ã«ã€ããŠãPVS-Studioã§æ°ãã蚺æã«ãŒã«ãäœæããŸãããçªç¶ãNullable <T>ã䜿çšãããšããããã³ã°åäœã«äºæããªãç¬éãããããšã倿ããŸãããç§ãã¡ã¯ãILã³ãŒããèŠãŠ-ããã¯ã¹ãªã©ã®ããã¯ã¹..ãCLI仿§ãã芧ãã ãã-ãããããã ãã§ãïŒããã¯ããªãè峿·±ãã±ãŒã¹ã®ããã§ãäžåºŠã ãèšã䟡å€ããããŸãã-ãããŠèšäºã¯ããªãã®ç®ã®åã«ãããŸãã

ãã®èšäºãè±èªã話ãèŽè¡ãšå ±æãããå Žåã¯ã翻蚳ãªã³ã¯SergeyVasilievã䜿çšããŠãã ãããnullå¯èœãªå€ã®ã¿ã€ããã©ã®ããã«èŠããŠãããã確èªããŠãã ããããã³ãããã®äžãèŠããŠã¿ãŸãããã
PPSã¡ãªã¿ã«ãæè¿ç§ã¯Twitterã§ããå°ã掻åçã«ãªããè峿·±ãã³ãŒãã¹ãããããæçš¿ãããã.NETã®äžçããã®è峿·±ããã¥ãŒã¹ããªãã€ãŒããããããŠããŸããèå³ãããã°ã確èªããããšããå§ãããŸã-ãµãã¹ã¯ã©ã€ãïŒãããã¡ã€ã«ãžã®ãªã³ã¯ïŒã