public void DoFoo<T>(T foo) where T : ISomeInterface<T> { //possible compare of value type with 'null'. if (foo == null) throw new ArgumentNullException("foo"); }
I'm purposely only checking against null because I don't want to restrict a ValueType
from being equal to its default(T)
. My code compiles and works just fine this way (ReSharper complains, but not CodeAnalysis). Though I do wonder:
The definition of a generic type should never be nullable. The nullability should be defined by the one using this generic. With the current Kotlin version, you can have a "String?" implementation and a "String" implementation.
Nullable types are neither value types nor reference types.
In C#, you can assign the null value to any reference variable. The null value simply means that the variable does not refer to an object in memory. You can use it like this: Circle c = new Circle(42); Circle copy = null; // Initialized ... if (copy == null) { copy = c; // copy and c refer to the same object ... }
Nullable variables may either contain a valid value or they may not — in the latter case they are considered to be nil . Non-nullable variables must always contain a value and cannot be nil . In Oxygene (as in C# and Java), the default nullability of a variable is determined by its type.
I'm purposely only checking against
null
because I don't want to restrict a ValueType from being equal to itsdefault(T)
That is a good insight, but don't worry, you are already covered there. It is not legal to compare a T against default(T)
using ==
in the first place; overload resolution will not find a unique best ==
operator.
Of course, you could do the comparison with .Equals
but then you run the risk of crashing if the receiver is null, which is precisely what you are attempting to avoid.
Is there a more standard way to handle this situation?
No. Comparing to null is the right thing to do here.
As the C# specification says in section 7.10.6: "The x == null
construct is permitted even though T could represent a value type, and the result is simply defined to be false when T is a value type."
Is there any chance of an issue arrising from this?
Sure. Just because code compiles does not mean that it has the semantics you intend. Write some tests.
What truly happens under the hood when I make a call and pass in a value type?
The question is ambiguous. Let me rephrase it into two questions:
What truly happens under the hood when I make a call on the generic method with a type argument that is a non-nullable value type?
The jitter compiles the method on the first invocation with that construction. When the jitter detects the null check, it replaces it with "false" because it knows that no non-nullable value type will ever be equal to null.
What truly happens under the hood when I make a call on the generic method with a type argument that is a reference type but an argument that is a struct type? For example:
interface IFoo : ISomeInterface<IFoo> {} struct SFoo : IFoo { whatever } ... DoFooInternal<IFoo>(new SFoo());
In that case the jitter cannot elide the null check and the call site cannot avoid the boxing. The SFoo instance will be boxed, and the reference to the boxed SFoo will be checked to see if it is null.
No, there won't be any problems, but if you want the warning to disappear, you can use the following:
public void DoFoo<T>(T foo) where T : ISomeInterface<T> { if (ReferenceEquals(foo, null)) throw new ArgumentNullException("foo"); }
Alternatively you can do something like this:
// when calling this with an actual T parameter, you have to either specify the type // explicitly or cast the parameter to T?. public void DoFoo<T>(T? foo) where T : struct, ISomeInterface<T> { if (foo == null) { // throw... } DoFooInternal(foo.Value); } public void DoFoo<T>(T foo) where T : class, ISomeInterface<T> { if (foo == null) { // throw... } DoFooInternal(foo); } private void DoFooInternal<T>(T foo) where T : ISomeInterface<T> { // actual implementation }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With