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
NullReferenceException when reading a virtual member with a *value type* return type in the c'tor #368
Comments
Very detailed analysis, @ulrichb. Thanks. And thanks for the note about #367, which I hadn't meant to change completely into a discussion about the exception message, but am still happy about having an issue about the exception messages when constructors fail. As you suggest, I will update the title. |
@blairconrad Many thanks! |
For what it's worth, I also like the idea of attaching the FakeManager earlier, for many of the same reasons. I'm not sure this is going to be an easy thing, though. |
To quote @ulrichb in a heretofore private conversation:
That's very encouraging. @ulrichb, may we consider the issue taken by you? |
Isn't this just one aspect of the more general #371? |
It is, but predates it. I believe @ulrich had started to work on this, but had realized that the way to fix it was to fix the more general issue. |
@adamralph Yes, exactly (I also mentioned it in the description of #371). I created 2 separate issues because a) I think this is a bug and #371 is a new feature that goes far beyond solving just this NullReferenceException and b) as mentioned above this issue could also be solved simpler by just escaping unhandled value type results in the Castle interceptor. |
Shall we re-label this as a bug? |
I'm not fussy. As always, it's in the eye of the beholder. Whatever you want to do, I'm happy. |
Interesting... OK, I'll ask a different question: Does adding this feature/fixing this bug provide any value? I.e. if the exception is not thrown, is the fake still usable? |
Merging #373 would cause the exception not to be thrown, and calls to virtual members from the faked class's constructor would act as if they were unconfigured methods that were called after proxy construction. Of course, if the fake's private members were initialized with the return values of the virtual methods, the client may not be able to further configure their actions (unless there's an accessor, I suppose). @ulrichb has a further PR (the bits that we sliced off #373) in the wings to provide that functionality. As I understand this issue and the PR that we're reviewing for it, there is value. I would be happy to see the functionality [fixed|added], and would not object to releasing a package with it, although there's more benefit if we take the second PR as well. Does that have the information you were hoping for? |
For my feeling it's a bug because when we have such a class (read access in c'tor to virtual member with value type return value), we aren't able to instantiate |
Fixed by #373. |
I've relabelled as a bug, as per earlier discussion. |
@blairconrad, @adamralph many thanks! |
Ah, yes! Thanks. |
@ulrichb, thanks very much for your work on this issue. Look for your name in the release notes. 🏆 This issue has been fixed in release 1.25.0. https://www.nuget.org/packages/FakeItEasy/1.25.0 |
BTW: Yes of course, the virtual calls in the c'tor are an anti-pattern.
I saved the generated proxy assembly and decompiled
get_VirtualInt
where the exception is thrown, and mentioned that the exception is caused by the cast toint
in the return statementreturn (int) t_s.ReturnValue;
. (Unboxing null results in a NullReferenceException.)Why has
ReturnValue
a value of null? Because during the c'tor execution, theFakeManager
hasn't attached to the proxy (=>ProxyInterceptor.CallWasIntercepted
is still null). And therefore theReturnValue
won't be set and stays at the value of null. Normally (outside of the c'tor) this cannot happen, because theDefaultReturnValueRule
fallback would returndefault(T)
for value types. BTW, this is one part of the problem of #365, because during the c'tor the interceptor cannot delegate to theFakeManager
and therefore the c'tor cannot use an already configured mock.I have 2 suggestions to solve this issue:
ProxyInterceptor
and ensure, that we never return null for value types (escape todefault(T)
)VirtualInt
would return0
in my example andVirtualString
would return the empty string instead of null).I would prefer the second option because a) I think it's nice that the virtual members behave the same way inside/outside of the c'tor and b) this would solve one part of #365, as mentioned above.
Note that the issue described above is the root cause for the
FakeCreationException
mentioned in #367 (I created a new one because the discussion in #367 is now just about the missing inner exception message; I recommend changing the title).It was also mentioned in #365 (comment) (the wrapped
NullReferenceException > TargetInvocationException > FakeCreationException
).The text was updated successfully, but these errors were encountered: