Recently,i found some code like Material s_DefaultUI = (Material) null; in Unity Graphic source code.But i don`t know why there has a cast operation.what's the benefit ?Thanks for your help!
Casting null to a nullable type, in a assignment to a explicitly typed variable, doesn't do anything and doesn't change anything, it's the same as not casting it at all, the only times when casting null to a type has a "benefit" is when:
1) You have multiple signatures of the same method which have different nullable types on the same position, e.g.:
void CheckIfNull(string s);
void CheckIfNull(Material m);
In this case, doing CheckIfNull(null) won't work because, it doesn't know to which sig the specified null should be passed to, so doing CheckIfNull((Material)null) will solve the issue.
2) If you have a value type which accepts a nullable type via a explicit conversion, e.g.:
struct StructA
{
public StructA(object obj) { }
public static explicit operator StructA(object obj)
{
return new StructA(obj);
}
}
void Stuff()
{
StructA myStruct = (StructA)null;
}
3) When using a implicitly typed variable, if s_DefaultUI was a var you would need to cast the null because, var is a auto type so it wouldn't know what the provided null's type is.
Other then that, AFAIK, there is no point in casting a null to a type, especially to a class type.
Related
I came across an interesting facet of the C# language this morning I have not experienced yet; consider the below code snippet:
public class Example
{
public int getInt()
{
int? myInt = 2;
return myInt; // <-- compiler error.
}
public object getObject()
{
object? obj = new { };
return obj; // <-- OK, no error.
}
}
The compiler returns an error on the commented line above:Error CS0266: Cannot implicitly convert type 'int?' to 'int'. An explicit conversion exists (are you missing a cast?) (CS0266)
What I find interesting is that the object example works just fine without complaining. I am assuming this is something to do with primitives vs. objects but I am unable to find any resources. I am aware the return type is not matching the object type, I just thought it was curious that it works with objects and not a primitive. If anyone could share some links/provide an explanation as to why this is, it would be greatly appreciated.
int? is syntactic sugar for Nullable<int>, a generic type that is distinct from just plain int. Thus, you can't return a Nullable<int> in a method specified to return int.
object, like other reference types, is nullable by itself and doesn't need to be wrapped in Nullable<T>, and thus can match the return type of getObject() and be returned without error.
Similar to Chris' answer except the nullable object part.
The ? is just syntax sugar for the Nullable<T> generic type. This type implicitly inherits the type object. Because Nullable<T> inherits object, the nullable object can be returned as type object.
The Nullable<T> does not inherit int and therefore cannot be returned with a return type of int.
Here's whats actually going on
public class Example
{
public int getInt()
{
Nullable<int> myInt = 2;
return myInt; // <-- compiler error.
}
public object getObject()
{
Nullable<object> obj = new { };
return obj; // <-- OK, no error.
}
}
When you call this getInt() you are asking for an int, not for an int?. In this way, you can do this:
public int getInt()
{
int? myInt = 2;
if (myInt.HasValue)
{
return myInt.Value; // You must return .Value (int value)
}
else
{
/* You can dou something here, like change to default value and then return 'myInt.Value', p.e.*/
}
}
Anyway, you can use .HasValue to know if a nullable attribute is null or not, and return the non-null value with .Value.
In the other way, when you ask for getObject(), you expect an object, wich can be any kind of type. This is why you have no errors on there.
int? num = null;
How does it work under the hood? I always assumed Nullable is a class and today I was debugging and was surprised to see it's a struct. I checked the source code and found this implicit operator:
[System.Runtime.Versioning.NonVersionable]
public static implicit operator Nullable<T>(T value)
{
return new Nullable<T>(value);
}
It's obviously not the answer here since null is not an int. In addition the constructor is this:
[System.Runtime.Versioning.NonVersionable]
public Nullable(T value)
{
this.value = value;
this.hasValue = true;
}
So the constructor is not called either.
Is compiler using some synthetic sugar here?
type? t = null;
is recognized by the compiler and replaced with type? t = new type?(), which invokes the default constructor which in turn sets the object to all zeros. The property HasValue is backed by a boolean variable such that false is the correct initial value in this case.
In just about every place, these constructions are treated as though they were references to a an object of type type. In order to observe they aren't you would need a mutable struct. The compiler knows about type? in quite a few ways including checking the HasValue property when boxing and boxing to a null or a boxed type. If you manage to get a boxed type? the unboxer should be able to handle it, but there doesn't seem to be a way to get a boxed type? anymore unless you're writing extern functions.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is it safe for structs to implement interfaces?
Take this code:
interface ISomeInterface
{
public int SomeProperty { get; }
}
struct SomeStruct : ISomeInterface
{
int someValue;
public int SomeProperty { get { return someValue; } }
public SomeStruct(int value)
{
someValue = value;
}
}
and then I do this somewhere:
ISomeInterface someVariable = new SomeStruct(2);
is the SomeStruct boxed in this case?
Jon's point is true, but as a side note there is one slight exception to the rule; generics. If you have where T : ISomeInterface, then this is constrained, and uses a special opcode. This means the interface can be used without boxing. For example:
public static void Foo<T>(T obj) where T : ISomeInterface {
obj.Bar(); // Bar defined on ISomeInterface
}
This does not involve boxing, even for value-type T. However, if (in the same Foo) you do:
ISomeInterface asInterface = obj;
asInterface.Bar();
then that boxes as before. The constrained only applies directly to T.
Yes, it is. Basically whenever you need a reference and you've only got a value type value, the value is boxed.
Here, ISomeInterface is an interface, which is a reference type. Therefore the value of someVariable is always a reference, so the newly created struct value has to be boxed.
I'm adding this to hopefully shed a little more light on the answers offered by Jon and Marc.
Consider this non-generic method:
public static void SetToNull(ref ISomeInterface obj) {
obj = null;
}
Hmm... setting a ref parameter to null. That's only possibly for a reference type, correct? (Well, or for a Nullable<T>; but let's ignore that case to keep things simple.) So the fact that this method compiles tells us that a variable declared to be of some interface type must be treated as a reference type.
The key phrase here is "declared as": consider this attempt to call the above method:
var x = new SomeStruct();
// This line does not compile:
// "Cannot convert from ref SomeStruct to ref ISomeInterface" --
// since x is declared to be of type SomeStruct, it cannot be passed
// to a method that wants a parameter of type ref ISomeInterface.
SetToNull(ref x);
Granted, the reason you can't pass x in the above code to SetToNull is that x would need to be declared as an ISomeInterface for you to be able to pass ref x -- and not because the compiler magically knows that SetToNull includes the line obj = null. But in a way that just reinforces my point: the obj = null line is legal precisely because it would be illegal to pass a variable not declared as an ISomeInterface to the method.
In other words, if a variable is declared as an ISomeInterface, it can be set to null, pure and simple. And that's because interfaces are reference types -- hence, declaring an object as an interface and assigning it to a value type object boxes that value.
Now, on the other hand, consider this hypothetical generic method:
// This method does not compile:
// "Cannot convert null to type parameter 'T' because it could be
// a non-nullable value type. Consider using 'default(T)' instead." --
// since this method could take a variable declared as, e.g., a SomeStruct,
// the compiler cannot assume a null assignment is legal.
public static void SetToNull<T>(ref T obj) where T : ISomeInterface {
obj = null;
}
The MSDN documentation tells us that structs are value, not reference types. They are boxed when converting to/from a variable of type object. But the central question here is: what about a variable of an interface type? Since the interface can also be implemented by a class, then this must be tantamount to converting from a value to a reference type, as Jon Skeet already said, therefore yes boxing would occur. More discussion on an msdn blog.
I don't get it. The As operator:
Then why does the following work?
struct Baby : ILive
{
public int Foo { get; set; }
public int Ggg()
{
return Foo;
}
}
interface ILive
{
int Ggg();
}
void Main()
{
ILive i = new Baby(){Foo = 1} as ILive; // ??????
Console.Write(i.Ggg()); // Output: 1
}
Baby is a struct, creating it will put value in stack. There is no reference involve here.
There are certainly no nullable types here.
Any explanation as to why I'm wrong?
Casting it as an interface will create a boxed copy on the managed heap , and return a reference to the boxed copy. The box implements the interface.
It works because the right hand side is an interface. The condition is that the right hand side can accept null as value, i.e. it's a reference type or a nullable value type. Interfaces are a reference types. In this case the code will box the struct and then cast the boxed object to the interface.
You simply cast with reference type ILive nullable value, so no error is thrown. However if you try this commented code, you will get an error.
Baby b = new Baby ();
object o = b;
//Baby bb = o as Baby ;
This is because you are trying to cast with as to value type and that can not be null.
Is there anything wrong with using an implicit operator like the following:
//linqpad c# program example
void Main()
{
var testObject = new MyClass<int>() { Value = 1 };
var add = 10 + testObject; //implicit conversion to int here
add.Dump(); // 11
}
class MyClass<T>
{
public T Value { get; set; }
public static implicit operator T (MyClass<T> myClassToConvert)
{
return myClassToConvert.Value;
}
}
I was thinking I could treat as instance of the object as a value type this way, but seeing as I've never seen an example of this I thought maybe there was a reason not to do something like this that someone could point out?
In my actual code I was thinking of doing this as part of a data abstraction layer, so that I could return objects with information describing the underlying data, but allow the logic code to treat it as a value type when all it needs to know about is the value, and at the same time keep it all nice and type safe with the generics.
If all of the following are true:
all possible values of your MyClass<T> type (including null if it’s not a value type!) map to a valid value of T
the implicit operator never throws (not even for null!)
the implicit conversion makes semantic sense and is not confusing to the client programmer
then there is nothing wrong with this. Of course you could do any of these three things, but it would be bad design. In particular, an implicit operator that throws can be very hard to debug because the place where it is called doesn’t say that it is being called.
For example, consider that T? has no implicit conversion to T (where T is, of course, a value type). If there was such an implicit operator, it would have to throw when the T? is null, as there is no obvious value to convert null to that would make sense for any value type T.
Let me give an example where I had trouble debugging an issue where the implicit operator threw:
public string Foo()
{
return some_condition ? GetSomething() : null;
}
Here, GetSomething returned something of a type I wrote which has a user-defined implicit conversion to string. I made absolutely sure that GetSomething could never return null, and yet I got a NullReferenceException! Why? Because the above code is not equivalent to
return some_condition ? (string)GetSomething() : (string)null;
but to
return (string)(some_condition ? GetSomething() : (Something)null);
Now you can see where the null came from!
That's a great pattern. Just keep in mind that in order to use it as a variable of type T, you have to either explicitly cast it to T, or assign it to a variable of type T. The cast will take place automatically in method calls and other things (such as your addition example) that take a T.
Implicit conversion without assignment?