This is more a question out of curiosity than necessity and came about having had to deal with Active Directory (MS) types such as SearchResultCollection
(in the System.DirectoryServices
namespace).
Frequently when dealing with AD in code, I find that I'm having to check values for null, Count, [0] .. whatever and convert what I get out .. all the while hoping that the underlying AD object via COM doesn't go poof etc.
After having a play about with Parallel.ForEach
recently - and having to pass in an IEnumerable<T>
, I thought, maybe it would be fun to see how I could cast a SearchResultCollection
to an IEnumerable
of my own custom type. In this type I would pull out all the values from the SearchResult
object and stick them in my own, .NET managed code. Then I'd do away with the DirectoryEntry
, DirectorySearcher
etc. etc.
So, having already worked out that it's a good idea to do searchResultCollection.Cast() in order to supply Parallel.ForEach with it's source, I added an explicit operator for casting to my own type (let's just call it 'Item
').
I tested this out within the ParallelForEach
, var myItem = (Item)currentSearchResult
.
Good times, my cast operator is called and it all works. I then thought, it would be nice to do something like searchResultCollection.Cast<Item>()
. Sadly this didn't work, didn't hit any breakpoints in the cast operator.
I did some Googling and discovered a helpful post which Jon Skeet had answered:
The crux of it, use .Select(...) to force the explicit cast operation. OK, but, hmmm.
I went off and perhaps disassembled System.Core
-> System.Linq.Enumerable.Cast<TResult>
, I noticed that this 'cast' is actually doing an 'as' keyword conversion under the hood:
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
{
IEnumerable<TResult> enumerable = source as IEnumerable<TResult>;
if (enumerable != null)
{
return enumerable;
}
if (source == null)
{
throw Error.ArgumentNull("source");
}
return CastIterator<TResult>(source);
}
I read some more and found this:
Implicit/Explicit conversion with respect to the "as" keyword
The top answer here states that 'as
' doesn't invoke any conversion operators .. use a (cast). Semantically I find this a little weird, since the extension method is called cast.. Shouldn't it be casting? There will no doubt be a really good reason why this doesn't happen, anyone know what it is?
Even if it would have used the cast operator instead of as
it still wouldn't be invoking user defined explicit operators, so it wouldn't matter. The only difference would be the type of exception thrown.
Explicit operators aren't known at all by the runtime. According to the CLR there is no way to cast your search result to Item
. When the compiler notices that there is a cast that matches a given explicit operator it injects at compile time a call to that explicit operator (which is basically a static method) into the code. Once you get to runtime there is no remaining knowledge of the cast, there is simply a method call in place to handle the conversion.
Because this is how explicit operators are implemented, rather than providing knowledge to the runtime of how to do the conversion, there is no way for Cast
to inject the explicit operator's call into the code. It's already been compiled. When it was compiled there was no knowledge of any explicit operator to inject, so none was injected.