NRT: How to correctly annotate my generic-class when inheriting from another generic class?
Hello. I'm trying to correctly annotate nullable reference types (NRT) to a generic class derived from another generic class.
Here is some simplified code:
The shown implementation triggers the CS8604 as commented which I understand. But how do I tell the compiler: I don't know if the user will use a nullable type or not for
K
?
When I change Dictionary<T, K>
to Dictionary<T, K?>
intellisense says that even my instance tmp
can have null
s added but my type parameter clearly states that I don't want that to be allowed.
So how do I correctly annotate this kind of scenario (I have a couple more like that)?
Thanks in advance31 Replies
what do you mean by
my type parameter clearly states that I don't want that to be allowed?
the problem is that IOther.Get always returns a nullable value
MyDictionary<Guid, string>
<- No ?
on string
.if I do
MyDictionary<string, object>
, then IOther.Get returns object?
then you try to call Add
, which takes K
, which is object
(not nullable)
aka you're trying to pass K?
as K
Exactly
what exactly do you want the compiler to do about that
you're doing something you explicitly said you wouldn't do
like, it doesn't matter what the actual user of your class does, you are allowing them to pass in
object
as K
your type parameter doesn't say at all that you don't want nulls
you have to pick one, either make Get not return nulls or the dictionary has to be allowed to contain nulls
you can't have bothI can't decide whether
K
will be nullable or notit depdends on the impl of the dependency really. if it can return a null value regardless of whether
K
is nullable or not, then there's nothing you can do about it. you have to assume that Get<K>
will return null in some cases. that's what the dependency says..
you are the one picking this
it has nothing to do with the users of the class
it's a dependency, they're not the one picking it
they can always throw on nulls or make a new interface
My problem/question is: How do I implement
MyDictionary<T, K> : Dictionary<T, K>
where I can leverage NRT and it's up to an actual consumer of that type if he wants to allow null or not.it's not up to you. the dependency says it can return null
what do you do when IOther returns null when the user said it can't contain nulls
That's my problem xD
I can't just check against null...
I mean, that's not something the compiler can help you with at all
it's a design choice
yes you can?
x.Get<K>() is null
works just fineThat's true. But I can't decide whether the used
K
from the consumer allows null or not.that doesn't matter here at all
even when
K
in MyDictionary<T, K>
is not nullable, the return value of Get<K>
is
they're unrelatedyes, it has to purely be a design consideration of your implementation
I believe they essentially want
which yeah, you can't do
that information isn't available to the implementation, NRTs are purely compile time
I just skimmed through the
List<T>
implementation. Maybe I have to use <T, K>
and use something like this
https://github.com/dotnet/runtime/blob/5535e31a712343a63f5d7d796cd874e563e5ac14/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs#L225GitHub
runtime/src/libraries/System.Private.CoreLib/src/System/Collections...
.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps. - dotnet/runtime
that throw helper is for value types
it only works when assigning
object
to T
where T is a non-nullable value type
aka it doesn't work for you
I meant it when I said this information is not available at runtimeYeah I know it's only compile time 🤔
So I have to either try change my dependency or suppress the warning with
!
and hope for the best 🥴if you can control the dependency, then you should change the implementation, yes
Get<K>
should only return K
, and a TryGet
method would be nice to have as well
i assume K? Get<K>
means a potential failure in getting
that info should be conveyed through other meansNo it really means
K
could be null
here.i'm not really sure what you mean.
Get<K>
can return null even when K
may not be nullable?
that's what it currently means💡 let me check
And that's exactly what it does. Returning
null
even if K
would be string
🤔in what circumstance? and is there no
TryGet
method?There is no
TryGet
and if it fails to get & convert that value.that's bad design by that api then
a failure like that should throw, not return null
I agree
Thank you for your answers. That was very enlightening.
i can't really think of a good way to handle this in that case. you would need to provide your own implementation of
IOther