Closed Saibamen closed 1 year ago
Can you provide a minimal but complete project that reproduces the exception you're reporting? Otherwise there's nothing we can do here.
Actually, never mind. This cannot be caused by Moq. My guess is that you have some other dependency installed that relies on Castle.Core v4 (possibly Windsor), and your updating Moq now forces v5 of that library. I suggest you either update those other dependencies, or you downgrade Moq.
Sorry, it has nothing to do with Moq
In my EFCore project, I used IsNullOrEmpty
extension for dictionary from Castle.Core.Internal
namespace (https://github.com/castleproject/Core/blob/v4.4.1/src/Castle.Core/Core/Internal/CollectionExtensions.cs).
I changed it to Microsoft.IdentityModel.Tokens
namespace
It looks like, even though we don't have a direct reference to Castle.Core.Internal in our own project, ReSharper picked up on the transitive reference and "helped" add the reference to enable a call to IsNullOrEmpty at some point in our history.
The really bizarre thing is that the code breaks at the point before it calls the method with the IsNullOrEmpty in it. It's somehow psychic. We have no problem compiling the code, but at runtime it breaks when you mention the code with the IsNullOrEmpty call in it. It never even enters the method itself. I put a breakpoint in the method before it calls IsNullOrEmpty, and the method is never even entered. It's spooky. Replacing the IsNullOrEmpty call with Foos?.Any() == true
accomplishes the same thing, but eliminates the error.
This is some voodoo here. I'm going to just walk away.
@MelGrubb, I'm guessing that this could be just-in-time (JIT) compilation at work. The following explanation may be somewhat inaccurate but maybe it aids your understanding nevertheless: .NET compiles methods to assembly code the first time it encounters them. That is, say you have a method M
that calls method X
, which during the execution of your program has never been called before. When it encounters a call instruction in method M
for method X
, it needs to compile X
before X
can actually run. And if X
's bytecode contains a reference to any type or type member that cannot be resolved (say, the IsNullOrEmpty
thingy you mention... e.g. due to the referenced assembly missing), then compilation of X
cannot complete and X
cannot be called at all, so your breakpoint will never be hit because execution gets stuck in M
.
Since the class that the problem occurs in has quite definitely been compiled by this point, and has been used throughout the test, I would think it had been compiled already. I was unaware that it would compile it piecemeal like that. Still, if Castle.Core hid the IsNullOrEmpty method between v4 and v5, I ought to be getting a compilation error, shouldn't I? If that method isn't visible anymore, then Intellisense shouldn't be suggesting it.
The weird part is that the error would happen in the code calling my method and not in the method itself. It does smell like some kind of JIT issue, and my only guess at this point is that somehow I have a v4 Castle.Core "visible" when writing the code that gets replaced by a v5 at runtime. It's the only explanation that makes sense to me.
Anyway, I've just dropped in my own IsNullOrEmpty extension in, and everything is back to normal again. Thanks for the follow-up.
Had the same issue. Interestingly IsNullOrEmpty of type IEnumerable was used on a string, which shouldn't be possible at all?
System.TypeLoadException : Could not load type 'Castle.Core.Internal.CollectionExtensions' from assembly 'Castle.Core, Version=5.0.0.0
after updating from Moq 4.18.3 to Moq 4.18.4