Why does the first function compile and the second emit a warning? Are the two implementations not equivalent? The type of valT
is T
in both implementations.
https://dotnetfiddle.net/XV5AXU
T To1<T>(object? val)
{
if (!(val is T valT))
{
throw new InvalidCastException();
}
return valT;
}
T To2<T>(object? val)
{
var valT = (T)val;
return valT; // Possible null reference return
}
Preface : You probably do not need to implement a generic "Cast" method. Be careful when implementing generic methods in C# for performance to avoid boxing (avoid using object
). Additionally if you hide the actual explicit cast operator in a generic method then the C# compiler can't give the consuming code early warning that a cast is provably incorrect.
Consider:
Int32 i = new Int32();
String s = (String)o; // <-- CS0030 Cannot convert type 'int' to 'string'
But with your code:
Int32 i = new Int32();
String s1 = To1<String>( i ); // No compiler error, despite incompatible types.
String s2 = To2<String>( i ); // Also no compiler error.
As for your questions:
Are the two implementations not equivalent?
No. See what happens when you pass val: null
:
// Using your functions `To1` and `To2`:
String strFromObj = To1<String>( new Object() ); // throws InvalidCastException (thrown from your code)
String strFromNull = To1<String>( null ); // throws InvalidCastException (thrown from your code)
String strFromObj = To2<String>( new Object() ); // throws InvalidCastException (thrown from the operator)
String strFromNull = To2<String>( null ); // returns null;
Why does the first function compile and the second emit a warning?
is
operator, which is safe and will never throw (note that it is your code which is throwing InvalidCastException
in this case).InvalidCastException
if T
is incorrect, unless the operand is null
.foo is T bar
operator tests the type of non- null
values . If foo
is null
then the is
expression returns false and bar
is default(T)
.T bar = (T)foo
cast expression will cast null
values but only if T
is a reference type - but this syntax may also invoke a custom explicit conversion operator instead of performing a cast. Also note that C# 8.0's nullable-reference-types feature ( object?
) is not enforced at runtime: the compiler does not add throw new ArgumentNullException
statements to your compiled code , so if you change your code to use object
instead of object?
you should still add if( val is null ) throw new ArgumentNullException( nameof(val) );
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.