Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReferenceEquals and Nullable<T>

While writing a unit test, I wanted to use Assert.AreSame(..) against a Nullable<T> type and I got unexpected results. Then I realized that the below code fails:

int? k = 10;
Assert.IsTrue(ReferenceEquals(k, k));

What is happening here?

Also, how can I make sure my method is returning the very same instance I passed to the mock/stub and not just doing return 10?

Edit:

I usually do the following to make sure I'm getting consistent results in my unit tests:

//Arrange
var result = new string(new[] {'1', '2', '3'});
mock.SetUp(x => x.Method("something").Returns(result);

//Act here

//Assert
Assert.AreSame(result, instance.ValueAssigned);

If I do return "123" inside Method(..), the above test will fail. I was trying to find a way of doing the same with Nullable.

like image 495
Oscar Mederos Avatar asked Nov 20 '13 04:11

Oscar Mederos


People also ask

What happens when nullable reference types are enabled?

When nullable reference types are enabled, the C# compiler emits warnings for any uninitialized non-nullable property, as these would contain null. As a result, the following, common way of writing entity types cannot be used:

Should I use == or referenceequals to check for NULL values?

In terms of null checks, the two should always return the same results. If a non-null reference ever equals null (even when using the Null Object pattern), regardless of whether ReferenceEquals or the == operator was used, it's a very bad thing.

Does EF Core support nullable reference types?

This page introduces EF Core's support for nullable reference types, and describes best practices for working with them. The main documentation on required and optional properties and their interaction with nullable reference types is the Required and Optional Properties page. It is recommended you start out by reading that page first.

Is it possible to make a reference non-nullable by default?

This implies, of course, a breaking language change such that reference types with no modifier are non-nullable by default. Switching standard reference declarations (no nullable modifier) to be non-nullable is perhaps the most difficult of all the requirements to reduce nullable idiosyncrasy.


1 Answers

What is happening here?

Both arguments are being boxed, to different objects.

Imagine your code is actually this:

int? k = 10;
object x = k; // Boxing operation 1
object y = k; // Boxing operation 2
Assert.IsTrue(ReferenceEquals(x, y));

Don't forget that nullable value types are still value types - so they get boxed when you convert them to reference type expressions.

Also, how can I make sure my method is returning the very same instance I passed to the mock/stub and not just doing return 10?

For value types, that question simply doesn't make sense. Basically, use Assert.AreSame for reference types, and Assert.AreEqual for value types. Note that this is independent of nullability. Assert.AreSame(10, 10) will fail too.

like image 175
Jon Skeet Avatar answered Sep 20 '22 05:09

Jon Skeet