-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hot Reload breaks MethodInfo
equality
#69427
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
Tagging subscribers to this area: @dotnet/area-system-reflection Issue DetailsDescriptionThis is very similar to #67989, but with an important difference. That other issue states that:
It seems that Hot Reload appears to break Reproduction StepsHere's a short console app that you'll need to run twice: once without making any code changes; and a second time by making any code change while var method1 = typeof(IInterface).GetMethod("Method")!;
Console.WriteLine("Hot reload here.");
Console.ReadLine();
var method2 = typeof(IInterface).GetMethod("Method")!;
Console.WriteLine(method1.ReflectedType == method2.ReflectedType && method1.Module == method2.Module && method1.MetadataToken == method2.MetadataToken);
Console.WriteLine(method1 == method2);
Console.WriteLine(method1.Equals(method2));
public interface IInterface
{
void Method();
} Expected behaviorIn both cases (without & with making any code changes), the expected output of the console app should be:
Actual behaviorWhen making a code change and Hot Reload's Apply Code Changes is performed, the output will be:
Regression?No response Known WorkaroundsI suppose one could do what the repro code does, and use Configuration
Other informationNo response
|
It is not possible to change existing references held by user code during a hot reload. Hot reload in general just clears runtime caches, so any existing references in memory will still be there and thus fail comparison against newly-created ones. If we wanted to preserve existing references, the underlying cache could use However, it is likely feasible to have |
We'd want to make sure this didn't negatively impact the performance of equality, in particular for inequality (since reference equality could still be used for the fast path). We might look to make any additions here conditioned on the process being configured for hot reload. |
Closing as duplicate of #67989 assuming that we implement a proper |
We should treat this and #67989 as two separate bugs. |
The fix here is to implement Equals() + GetHashCode() on The implementation would likely compare Module+Token, perhaps with a @stakx what is your real-world scenario and priority of getting this fixed? Is it just a timing issue as shown in the main description, or is |
@steveharter, I've opened this issue here as a reaction to devlooped/moq#1252. In short, using Hot Reload in conjunction with Moq, a rather popular .NET mocking library, can lead to the faulty behavior described. It's not just a timing issue; it breaks the debugging experience by introducing fake errors that wouldn't be there during "normal" code execution not involving Hot Reload. Moq caches I can't say how urgently Moq users need this fixed (these days I only maintain the library, I don't actively use it myself); I suppose one can simply switch off Hot Reload and all is well. Except that (a) you guys probably wants Hot Reload to work, and be used by devs, and (b) it simply seems wrong IMHO to leave something as fundamental as object equality broken. /cc @frenzibyte @peppy — maybe you can add a word on how this bug affects you in your work. |
I think the explanation and videos I included in devlooped/moq#1252 (comment) should summarise our use case quite well. Basically, our component testing framework pins on us being able to hot-reload and see UI changes. We want to use moq to isolate individual components for testing, and with this bug existing we are unable to easily integrate it without making |
Another option would be a public "cache iteration" counter (or event perhaps) -- if the counters are not equal on access, then the Moq caches should be cleared. E.g. // Moq cache access
if (Moq.MethodInfoCache.Iteration != MethodInfo.CacheIteration)
{
Moq.MethodInfoCache.Clear(); // Caches will be built-up again
Moq.MethodInfoCache.Iteration = MethodInfo.CacheIteration;
} |
The existing
This API would introduce hot-reload performance regressions. The reflection caches are cleared only partially. We are not clearing the cache e.g. for CoreLib methods since we know that CoreLib cannot be updated via hot-reload. It means that there is no uniform CacheIteration today. Also, updating all places that care about MethodInfo equality to check the CacheIteration would be very invasive for the ecosystem. |
If my understanding of I'm willing to give this a try, but what I don't understand is, why the push towards workarounds? Why not simply fix |
FieldInfo, PropertyInfo has same issue, should we fix those similar way too? What about other members? |
Yes, we should fix all reflection |
Should we also add an analyzer that would flag uses of People do run into this. @eerhardt just ran into it two weeks ago octokit/octokit.graphql.net#262 (comment) and it's also a pain to troubleshoot. ...unless we plan to get rid of targeting netstandard 1.x. |
Yes, we are slowly getting rid of netstandard 1.x targeting. From https://devblogs.microsoft.com/dotnet/the-future-of-net-standard : We’d generally recommend against targeting .NET Standard 1.x as it’s not worth the hassle anymore. Leading by example in #53283 |
Description
This is very similar to #67989, but with an important difference. That other issue states that:
It seems that Hot Reload appears to break
MethodInfo
equality even when theMethodInfo
s are obtained in exactly the same way. See the attached repro code example.Reproduction Steps
Here's a short console app that you'll need to run twice: once without making any code changes; and a second time by making any code change while
Console.ReadLine
is waiting for user input. For example, change the.
in"Hot reload here."
to a!
, then hit Apply Code Changes (then hit enter in the app's console window).Expected behavior
In both cases (without & with making any code changes), the expected output of the console app should be:
Actual behavior
When making a code change and Hot Reload's Apply Code Changes is performed, the output will be:
Regression?
No response
Known Workarounds
I suppose one could do what the repro code does, and use
method1.Module == method2.Module && method1.MetadataToken == method2.MetadataToken
instead ofmethod1.Equals(method2)
(though not sure whether that is guaranteed to work in all cases, e.g. with generic method instantiations)... but that obviously shouldn't be necessary.Configuration
Other information
No response
The text was updated successfully, but these errors were encountered: