The as operator on structures? - c#

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.

Related

Why must nullable primitives be casted as non null before returning from method in C#, yet complex objects do not?

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.

When exactly does boxing occur between a struct and interface in C# [duplicate]

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.

Trying to understand Type Casting & Boxing/Unboxing

I'm currently trying to get my head around casting and boxing. As i understand it currently:
Boxing - Value Type to Reference Type (ie int to object)
Unboxing - Reference Type to Value Type (ie object to int)
Type Casting - Seems to me at the moment to be similar to boxing but
allows you to assign what type of object you would like the Reference
Type to be of. (ie int to customObjectType)
The example im working with at the moment to try and get my around it.
Say I have 2 classes, a method in one class calls the constructor of the other.
//1st class
public class FirstClass
{
//code for fields,constructor & other methods
public void CallOtherClass(int firstClassID)
{
int x = firstClassID;
SecondClass test = new SecondClass(x);
}
}
//2nd class
public class SecondClass
{
public SecondClass(FirstClass firstClass)
{
//set some fields
}
}
Ok, so in the above scenario we would have a problem as the method CallOtherClass attempts to set the constructor of SecondClass, however the constructor of SecondClass takes a parameter of type FirstClass and all we can provide is an int.
So as i understand it this would be a good time to use type casting? Something like below.
//1st class
public class FirstClass
{
//code for fields,constructor & other methods
public void CallOtherClass(int firstClassID)
{
int x = firstClassID;
FirstClass a;
a = (FirstClass)x;
SecondClass test = new SecondClass(a);
}
}
//2nd class
public class SecondClass
{
public SecondClass(FirstClass firstClass)
{
//set some fields
}
}
In my head this seems to me to change the type of x to a reference type of FirstClass. Obviously my understanding is way off some where along the lines as it produces an error
"Cannot convert type 'int' to 'Namespace.FirstClass"
Any thoughts?
Type casting isn't boxing or unboxing, but it may cause either.
As an int isn't a FirstClass, that is, int doesn't inherit or extend FirstClass, hence you can't cast it to be of type FirstClass.
Typecasting causes conversion, only if it is possible to do so.
So you can go from an int to a double and vice versa, with possible side effects. But you can't go from an int to FirstClass.
Boxing, wraps a value or reference type in wrapper object. At least that's how I think of it. Not sure how the internals work, but my guess is the assignment operator "=" or casting implicitly returns the wrapped value when unboxing, and the wrapper object when boxing.

Nullable type as a generic parameter

I'm trying to implement a class that stores a generic nullable type:
public class myclass<T?>
{
T? myvariable;
public T? myfunction(){
return myvariable;
}
}
And while the above class compiles just fine, the actual use that provides trouble:
myclass<int?> c = new myclass<int>();
int? = c.myfunction(); // does not work: implicit cast from type T? in int? not possible.
// or, assuming the variable is not null
int = c.myfunction().Value; // implicit cast from type T in int not possible.
What am I doing wrong or how can I work around this?
Neither of the examples compile:
<T?> isn't valid syntax; it should be <T>
myclass needs a where T : struct constraint
The first line of your second example should read: myclass<int> c = new myclass<int>();.
The rest of your second example should compile OK, however.

why some unity source code assign null has a cast operation?

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.

Categories