I am looking for a way to explain that it’s unreasonable to sprinkle high-level business logic with calls to ReferenceEquals().
Here’s a code snippet that I have a problem with (precondition in a method, designed to throw if we’re on a wrong thread):
if (!object.ReferenceEquals(Thread.CurrentThread, RequestHandlerThread))
Is it reliable to write this instead:
if (Thread.CurrentThread != RequestHandlerThread)
I suggested to use ManagedThreadIds in the comparison based on what I commonly see in tutorials. Adversary says that comparison for reference equality seems more object-oriented.
Here’s (roughly) what I saw in Reflector’s view of System.Object with .NET 4.0. Keep in mind that Thread class is sealed, and has no overload for operator==.
public static bool ReferenceEquals(object objA, object objB)
{
return (objA == objB);
}
public static bool Equals(object objA, object objB)
{
return (objA == objB ||
(objA != null && objB != null && objA.Equals(objB)));
}
Here are some basic tests, verifying operation on thread pool… Did I miss any significant tests?
using System.Threading;
using System.Diagnostics;
using System.Threading.Tasks;
namespace ConsoleApplicationX
{
class Program
{
static readonly Thread mainThread;
static Program()
{
mainThread = Thread.CurrentThread;
}
static void Main(string[] args)
{
Thread thread = Thread.CurrentThread;
if (thread != Thread.CurrentThread)
Debug.Fail("");
if(Thread.CurrentThread != thread)
Debug.Fail("");
if (thread != mainThread)
Debug.Fail("");
var task = Task.Factory.StartNew(() => RunOnBackground(thread));
task.Wait();
var anotherThread = new Thread(new ParameterizedThreadStart(RunInAnotherThread));
anotherThread.Start(thread);
}
static void RunOnBackground(Thread fromInitial)
{
if (Thread.CurrentThread == fromInitial)
Debug.Fail("");
if (fromInitial != mainThread)
Debug.Fail("");
}
static void RunInAnotherThread(object fromInitialAsObject)
{
var fromInitial = (Thread)fromInitialAsObject;
if (Thread.CurrentThread == fromInitial)
Debug.Fail("");
if (fromInitial != mainThread)
Debug.Fail("");
}
}
}
Short answer:
Use ManagedThreadId property for comparisons.
Simple Example:
Imagine we have a class called StackOverflow.MessageThread. Programmer fat-fingers a precondition for a function, saying Debug.Assert(Thread.CurrentThread == messageThread). Precondition fails at runtime. If the dev would reach for ManagedThreadId, he’d find out at edit-time that it’s impossible, and would fix the problem earlier in the development cycle.