If I cast an object in C#, does it still reference the original object cast?
As an example, if I create a method to change an object and then cast that object depending on specific implementation called, does the original object get preserved?
public bool CallChangeString()
{
String str = "hello";
ChangeObject(str);
return String.Equals("HELLO", str);
}
public void ChangeObject(Object obj)
{
String str = obj as String;
str.ToUpper(); // pretend for the sake of this that this changes str to upper case
}
In this case, would the String.Equals return true or false?
Are there any situations where casting would cause the new object to not preserve it's reference?
Depends on what cast you are doing. You can think of two main groups of casting:
Those that preserve identity
Those that don't
Well, thats not very helpful, that is precisely what you are asking.
What casts don't preserve identity? All those that entail a representational change in the object itself, that is, the bits that make up the object change.
Examples? All casts between value types: int to long, int to double, etc., any boxing or unboxing conversion, etc. The bits that make up a long are very different from those that make up an int.
More examples? Any user defined cast operator, explicit or implicit. Why? Because user defined casts that preserve identity are disallowed by the compiler simply because the compiler already does them for you:
class Foo : IFoo
{
public static implicit operator object(Foo foo) => return foo; //Compile time error
public static implicit operator IFoo(Foo foo) => return foo; //compile time error.
public static explicit operator Bar(Foo foo) => return new Bar(foo);
}
Note the general pattern of user defined casts:
any valid operator will always have a new lurking
around in whatever it returns. Thats telling you right away that the
cast can not preserve identity... you are returning a new object.
There is no way you can implement a user defined identity preserving conversion. Thats not a problem because there is no need, those conversions are already provided by C#'s type system.
So, what are identity preserving casts or conversions? Well, those that don't touch the object all; reference conversions.
Huh? But wait, The whole point is that I'm casting the object, how can that be?
In reference conversions you are only "casting" the reference pointing to the object. The object is always the same. This, of course, only makes sense in reference types and that is why value types don't have identity preserving conversions; there are no references to value types unless they are boxed.
Examples? object to string, Foo to IFoo, Giraffe to Animal, etc.
Do note that reference types can very well implement user defined casts too, but these will not preserve identity.
All that said, this is the rule of the thumb:
Any cast provided/allowed by the language type system itself preserves identity. These are, exclusively, reference conversions and only apply to reference types.
Any user defined cast, explicit or implicit, does not preserve identity (rememeber, (long)2 is a user defined cast, somebody had to implement it in the class System.Int64).
So, answering your question, var str = obj as string is a reference conversion, which means that ReferenceEquals(str, obj) is true; str and obj point to exactly the same object, the only difference is the type of the reference.
strings are immutable, so you can't change them. However you can create new instances:
myString = myString.Replace("", ".");
Be aware that myString is a completely new instance which is not related to the original string. Thus even if you assign something different to myString this won't affect your calling code that relies on the original instance.
In your example str.ToUpper() won't change anything, as ToUpper returns a new string instead of changing the current (str) instance.
casting creates a new reference to the same instance. Thus modifications to an instance are reflected in all of its references, be it casted instances or just re-references
var a = (MyType) myInstance;
a.MyProperty = 4;
After the last statement both a and myInstance have the property MyProperty set to 4, because both variables a and myInstance reference the same instance of MyType.
Change your method like this and see result )
public bool CallChangeString()
{
String str = "hello";
ChangeObject(str);
return String.Equals("HELLO", str);
}
Related
I have an explicit operator on the class MyVO, which should be non-nullable.
public class MyVO : ValueObject<MyVO>
{
public string Value { get; } // Should never be null
private MyVO(string v) => Value = v;
public static explicit operator MyVO(string vo)
{
if (string.IsNullOrWhiteSpace(vo)) throw new Exception('...');
return new MyVO(vo);
}
However, (MyVO)null will not raise an exception. The body of the method will not be run.
var myVO = (MyVO)null; // myVO will have the null value
How to make sure it's not null?
How to make sure it's not null?
By "it" I assume you mean "the result of the cast from null to MyVO". If that is not what you mean, please clarify the question.
You cannot.
An important rule of C# is a user-defined conversion never "wins" when it conflicts with a built-in conversion. It is legal to convert null to any class type, and so a cast of MyVO on the expression null will always result in a null reference. The compiler does not even consider the user-defined conversions if a built-in conversion works. (Believe me; I wrote that code!)
As D Stanley's answer correctly points out, if the null is the value of any expression of type string then the user-defined conversion is called; there is no built-in conversion from string to MyVO so the compiler looks for an applicable user-defined conversion and finds one.
Since it hurts when you do what you're doing, you should probably stop doing what you are doing. An explicit conversion is probably not the right way to implement the desired behaviour.
I guess my question should be how to make MyVO not nullable.
Upgrade to C# 8. C# 8 supports non-nullable annotations on reference types.
Note that the non-nullable annotation should be properly thought of as an annotation. The type system does not guarantee that the value of a variable annotated with a non-nullable annotation will never be observed to be null. Rather, it does its best to warn you when the code looks like it is wrong.
While we are looking at your code, I notice that you are using ValueObject<T>, which I assume you have obtained from something like
https://enterprisecraftsmanship.com/posts/value-object-better-implementation/
Let me take this opportunity to caution you that there are pitfalls to using this pattern; the constraint that you think or want to be applied to T is not the constraint that is applied to T. We often see things like this:
abstract class V<T> where T : V<T>
{
public void M(T t) { ... } // M must take an instance of its own type
}
If we have class Banana : V<Banana> then Banana.M takes as its argument a Banana, which is what we want. But now suppose we have class Giraffe : V<Banana>. In this scenario, Giraffe.M does not take a giraffe; it takes a banana, even though Giraffe has no relationship with Banana at all.
The constraint does not mean that M always takes an instance of its own class. If you are trying to construct a generic type with this kind of constraint in C#, you cannot; the C# type system is not rich enough to express that constraint.
null can be implicitly converted to any reference type, so the compiler is not using your explicit cast operator. try
string s = null;
o = (MyVO)s;
or just inline it
o = (MyVO)((string)s);
This question already has answers here:
Direct casting vs 'as' operator?
(16 answers)
Difference between is and as keyword
(13 answers)
Closed 7 years ago.
Which method is best practice to type casting and checking ?
Employee e = o as Employee;
if(e != null)
{
//DO stuff
}
OR
if(o is Employee)
{
Employee e = (Employee) o;
//DO stuff
}
At least there are two possibilities for casting, one for type checking and a combination of both called pattern matching. Each has its own purpose and it depends on the situation:
Hard cast
var myObject = (MyType)source;
You normally do that if you are absolutely sure if the given object is of that type. A situation where you use it, if you subscribed to an event handler and you cast the sender object to the correct type to work on that.
private void OnButtonClick(object sender, EventArgs e)
{
var button = (Button)sender;
button.Text = "Disabled";
button.Enabled = false;
}
Soft cast
var myObject = source as MyType;
if (myObject != null)
// Do Something
This will normally be used if you can't know if you really got this kind of type. So simply try to cast it and if it is not possible, simply give a null back. A common example would be if you have to do something only if some interface is fullfilled:
var disposable = source as IDisposable;
if(disposable != null)
disposable.Dispose();
Also the as operator can't be used on a struct. This is simply because the operator wants to return a null in case the cast fails and a struct can never be null.
Type check
var isMyType = source is MyType;
This is rarely correctly used. This type check is only useful if you only need to know if something is of a specific type, but you don't have to use that object.
if(source is MyType)
DoSomething();
else
DoSomethingElse();
Pattern matching
if (source is MyType myType)
DoSomething(myType);
Pattern matching is the latest feature within the dotnet framework that is relevant to casts. But you can also handle more complicated cases by using the switch statement and the when clause:
switch (source)
{
case SpecialType s when s.SpecialValue > 5
DoSomething(s);
case AnotherType a when a.Foo == "Hello"
SomethingElse(a);
}
I think this is a good question, that deserves a serious and detailed answer. Type casts is C# are a lot of different things actually.
Unlike C#, languages like C++ are very strict about these, so I'll use the naming there as reference. I always think it's best to understand how things work, so I'll break it all down here for you with the details. Here goes:
Dynamic casts and static casts
C# has value types and reference types. Reference types always follow an inheritance chain, starting with Object.
Basically if you do (Foo)myObject, you're actually doing a dynamic cast, and if you're doing (object)myFoo (or simply object o = myFoo) you're doing a static cast.
A dynamic cast requires you to do a type check, that is, the runtime will check if the object you are casting to will be of the type. After all, you're casting down the inheritance tree, so you might as well cast to something else completely. If this is the case, you'll end up with an InvalidCastException. Because of this, dynamic casts require runtime type information (e.g. it requires the runtime to know what object has what type).
A static cast doesn't require a type check. In this case we're casting up in the inheritance tree, so we already know that the type cast will succeed. No exception will be thrown, ever.
Value type casts are a special type of cast that converts different value types (f.ex. from float to int). I'll get into that later.
As, is, cast
In IL, the only things that are supported are castclass (cast) and isinst (as). The is operator is implemented as a as with a null check, and is nothing more than a convenient shorthand notation for the combination of them both. In C#, you could write is as: (myObject as MyFoo) != null.
as simply checks if an object is of a specific type and returns null if it's not. For the static cast case, we can determine this compile-time, for the dynamic cast case we have to check this at runtime.
(...) casts again check if the type is correct, and throw an exception if it's not. It's basically the same as as, but with a throw instead of a null result. This might make you wonder why as is not implemented as an exception handler -- well, that's probably because exceptions are relatively slow.
Boxing
A special type of cast happens when you box a value type into an object. What basically happens is that the .NET runtime copies your value type on the heap (with some type information) and returns the address as a reference type. In other words: it converts a value type to a reference type.
This happens when you have code like this:
int n = 5;
object o = n; // boxes n
int m = (int)o; // unboxes o
Unboxing requires you to specify a type. During the unboxing operation, the type is checked (like the dynamic cast case, but it's much simpler because the inheritance chain of a value type is trivial) and if the type matches, the value is copied back on the stack.
You might expect value type casts to be implicit for boxing -- well, because of the above they're not. The only unboxing operation that's allowed, is the unboxing to the exact value type. In other words:
sbyte m2 = (sbyte)o; // throws an error
Value type casts
If you're casting a float to an int, you're basically converting the value. For the basic types (IntPtr, (u)int 8/16/32/64, float, double) these conversions are pre-defined in IL as conv_* instructions, which are the equivalent of bit casts (int8 -> int16), truncation (int16 -> int8), and conversion (float -> int32).
There are some funny things going on here by the ways. The runtime seems to work on multitudes of 32-bit values on the stack, so you need conversions even on places where you wouldn't expect them. For example, consider:
sbyte sum = (sbyte)(sbyte1 + sbyte2); // requires a cast. Return type is int32!
int sum = int1 + int2; // no cast required, return type is int32.
Sign extension might be tricky to wrap your head around. Computers store signed integer values as 1-complements. In hex notation, int8, this means that the value -1 is 0xFF. So what happens if we cast it to an int32? Again, the 1-complement value of -1 is 0xFFFFFFFF - so we need to propagate the most significant bit to the rest of 'added' bits. If we're doing unsigned extensions, we need to propagate zero's.
To illustrate this point, here's a simple test case:
byte b1 = 0xFF;
sbyte b2 = (sbyte)b1;
Console.WriteLine((int)b1);
Console.WriteLine((int)b2);
Console.ReadLine();
The first cast to int is here zero extended, the second cast to int is sign extended. You also might want to play with the "x8" format string to get the hex output.
For the exact difference between bit casts, truncation and conversion, I refer to the LLVM documentation that explains the differences. Look for sext/zext/bitcast/fptosi and all the variants.
Implicit type conversion
One other category remains, and that's the conversion operators. MSDN details how you can overload the conversion operators. Basically what you can do is implement your own conversion, by overloading an operator. If you want the user to explicitly specify that you intend to cast, you add the explicit keyword; if you want implicit conversions to happen automagically, you add implicit. Basically you'll get:
public static implicit operator byte(Digit d) // implicit digit to byte conversion operator
{
return d.value; // implicit conversion
}
... after which you can do stuff like
Digit d = new Digit(123);
byte b = d;
Best practices
First off, understand the differences, which means implementing small test programs until you understand the distinction between all of the above. There's no surrogate for understanding How Stuff Works.
Then, I'd stick to these practices:
The shorthands are there for a reason. Use the notation that's the shortest, it's probably the best one.
Don't use casts for static casts; only use casts for dynamic casts.
Only use boxing if you need it. The details of this go well beyond this answer; basically what I'm saying is: use the correct type, don't wrap everything.
Notice compiler warnings about implicit conversions (f.ex. unsigned/signed) and always resolve them with explicit casts. You don't want to get surprises with strange values due to sign/zero extension.
In my opinion, unless you know exactly what you're doing, it's best to simply avoid the implicit/explicit conversion -- a simple method call is usually better. The reason for this is that you might end up with an exception on the loose, that you didn't see coming.
With the second method, if the cast fails an exception is thrown.
When casting using as, you can only use reference types. so if you are typecasting to a value type, you must still use int e = (int) o; method.
a good rule of thumb, is : if you can assign null as a value to the object, you can type cast using as.
that said, null comparison is faster than throwing and catching an exception, so in most cases, using as should be faster.
I can't honestly say with certainty if this applies with your is check in place though. It could fail under some multi threading conditions where another thread changes the object you're casting.
I would use the as (safe-cast) operator if I need to use the object after casting. Then I check for null and work with the instance. This method is more efficient than is + explicit cast
In general, the as operator is more efficient because it actually returns the cast value if the cast can be made successfully. The is operator returns only a Boolean value. It can therefore be used when you just want to determine an object's type but do not have to actually cast it.
(more information here).
I am not sure about it but I think that is is using as under the hood and just returns if the object after casting is null (in case of reference types) / an exception was thrown (in case of value types) or not.
Well, it's a matter of taste and specifics of problem that you're dealing with. Let's have a look at two examples with generic methods.
For generic method with 'class' constraint (the safest approach with double cast):
public void MyMethod<T>(T myParameter) where T : class
{
if(myParameter is Employee)
{
// we can use 'as' operator because T is class
Employee e = myParameter as Employee;
//DO stuff
}
}
Also you can do someting like this (one cast operation here but defined variable of type that may or may not be correct) :
public void MyMethod<T>(T myParameter) where T : class
{
Employee e;
if((e = myParameter as Employee) != null)
{
//DO stuff with e
}
}
For generic method with 'struct' constraint :
public void MyMethod<T>(T myParameter) where T : struct
{
if(myParameter is int)
{
// we cant use 'as' operator here because ValueType cannot be null
// explicit conversion doesn't work either because T could be anything so :
int e = Convert.ToInt32(myParameter);
//DO stuff
}
}
Simple scenario with explicit cast:
int i = 5;
object o = (object)i; // boxing
int i2 = (int)o; // unboxing
We can use explicit cast here because we are 100% sure of what types do we use.
I was looking at this question, and aside from a rather odd way to enumerate something, the op was having trouble because the enumerator is a struct. I understand that returning or passing a struct around uses a copy because it is a value type:
public MyStruct GetThingButActuallyJustCopyOfIt()
{
return this.myStructField;
}
or
public void PretendToDoSomething(MyStruct thingy)
{
thingy.desc = "this doesn't work as expected";
}
So my question is if MyStruct implements IMyInterface (such as IEnumerable), will these types of methods work as expected?
public struct MyStruct : IMyInterface { ... }
//will caller be able to modify the property of the returned IMyInterface?
public IMyInterface ActuallyStruct() { return (IMyInterface)this.myStruct; }
//will the interface you pass in get its value changed?
public void SetInterfaceProp(IMyInterface thingy)
{
thingy.desc = "the implementing type is a struct";
}
Yes, that code will work, but it needs explanation, because there is a whole world of code that will not work, and you're likely to trip into that unless you know this.
Before I forget: Mutable structs are evil. OK, with that out of the way, let's move on.
Let's take a simple example, you can use LINQPad to verify this code:
void Main()
{
var s = new MyStruct();
Test(s);
Debug.WriteLine(s.Description);
}
public void Test(IMyInterface i)
{
i.Description = "Test";
}
public interface IMyInterface
{
string Description { get; set; }
}
public struct MyStruct : IMyInterface
{
public string Description { get; set; }
}
When executing this, what will be printed?
null
OK, so why?
Well, the problem is this line:
Test(s);
This will in fact box that struct and pass the boxed copy to the method. You're successfully modifying that boxed copy, but not the original s variable, which was never assigned anything, and is thus still null.
OK, so if we change just one line in the first piece of code:
IMyInterface s = new MyStruct();
Does this change the outcome?
Yes, because now you're boxing that struct here, and always use the boxed copy. In this context it behaves like an object, you're modifying the boxed copy and writing out the contents of the boxed copy.
The problem thus crops up whenever you box or unbox that struct, then you get copies that live separate lives.
Conclusion: Mutable structs are evil.
I see two answers about using ref here now, and this is barking up the wrong tree. Using ref means you've solved the problem before you added ref.
Here's an example.
If we change the Test method above to take a ref parameter:
public void Test(ref IMyInterface i)
Would this change anything?
No, because this code is now invalid:
var s = new MyStruct();
Test(ref s);
You'll get this:
The best overloaded method match for 'UserQuery.Test(ref UserQuery.IMyInterface)' has some invalid arguments
Argument 1: cannot convert from 'ref UserQuery.MyStruct' to 'ref UserQuery.IMyInterface'
And so you change the code to this:
IMyInterface s = new MyStruct();
Test(ref s);
But now you're back to my example, just having added ref, which I showed is not necessary for the change to propagate back.
So using ref is orthogonal, it solves different problems, but not this one.
OK, more comments regarding ref.
Yes, of course passing a struct around using ref will indeed make the changes flow throughout the program.
That is not what this question was about. The question posted some code, asked if it would work, and it would. In this particular variant of code it would work. But it's so easy to trip up. And pay particular note that the question was regarding structs and interfaces. If you leave interfaces out of it, and pass the struct around using ref, then what do you have? A different question.
Adding ref does not change this question, nor the answer.
Within the CLR, every value-type definition actually defines two kinds of things: a structure type, and a heap object type. A widening conversion exists from the structure type to the boxed object type, and a narrowing conversion exists from Object to the structure type. The structure type will behave with value semantics, and the heap object type will behave with mutable reference semantics. Note that the heap object types associated with all non-trivial structure types [i.e. those with any non-default states] are always mutable, and nothing in the structure definition can cause them to be otherwise.
Note that value types may be constrained, cast, or coerced to interface types, and cast or coerced to reference types. Consider:
void DoSomethingWithDisposable<T,U>(ref T p1,
List<int>.Enumerator p2) where T:IDisposable
{
IDisposable v1a = p1; // Coerced
Object v1b = p1; // Coerced
IDisposable v2a = (IDisposable)p2; // Cast
Object v2b = (Object)p2; // Cast
p1.Dispose(); // Constrained call
}
void blah( List<string>.Enumerator p1, List<int>.Enumerator p2) // These are value types
{
DoSomethingWithDisposable(p1,p2); // Constrains p1 to IDisposable
}
Constraining a generic type to an interface type does not affect its behavior as a value type. Casting or coercing an a value type to an interface or reference type, however, will create a new instance of the heap object type and return a reference to that. That reference will then behave with reference-type semantics.
The behavior of value types with generic constraints can at times be very useful, and such usefulness can apply even when using mutating interfaces, but unfortunately there's no way to tell the compiler that a value type must remain as a value type, and that the compiler should warn if it would find itself converting it to something else. Consider the following three methods:
bool AdvanceIntEnumerator1(IEnumerator<int> it)
{ return it.MoveNext(); }
bool AdvanceIntEnumerator2(ref T it) where T:IEnumerator<int>
{ return it.MoveNext(); }
bool AdvanceIntEnumeratorTwice<T>(ref T it) where T:IEnumerator<int>
{ return it.MoveNext() && AdvanceIntEnumerator1(it); }
If one passes to the first piece of code a variable of type List<int>.Enumerator, the system will copy its state to a new heap object, call MoveNext on that object, and abandon it. If one passes instead a variable of type IEnumerator<int> which holds a reference to a heap object of type List<int>.Enumerator, it will call MoveNext on that instance, which the calling code will still retain.
If one passes to the second piece of code a variable of type List<int>.Enumerator, the system will call MoveNext on that variable, thus changing its state. If one passes a variable of type IEnumerable<T>, the system will call MoveNext on the object referred to by that variable; the variable won't be modified (it will still point to the same instance), but the instance to which it points will be.
Passing to the third piece of code a variable of type List<int>.Enumerator will cause MoveNext to be called on that variable, thus changing its state. If that returns true, the system will copy the already-modified variable to a new heap object and call MoveNext on that. The object will then be abandoned, so the variable will only be advanced once, but the return value will indicate whether a second MoveNext would have succeeded. Passing the third piece of code a variable of type IEnumerator<T> which holds a reference to a List<T>.Enumerator, however, will cause that instance to be advanced twice.
No, interface is a contract, to make it work properly you need to use ref keyword.
public void SetInterfaceProp(ref IMyInterface thingy)
{
thingy.desc = "the implementing type is a struct";
}
What matters here is a real type that stays inside that interface wrap.
To be more clear:
even if code with method SetInterfaceProp defined like
public void SetInterfaceProp(IMyInterface thingy)
{
thingy.desc = "the implementing type is a struct";
}
will work:
IMyInterface inter= default(MyStruct);
SetInterfaceProp(inter);
this one will not :
MyStruct inter = default(MyStruct);
SetInterfaceProp(inter);
You can not gurantee that the caller of your method will always use IMyInterface, so to guarantee expected behavior, in this case, you can define ref keyword, that will guarantee that in both cases method would run as expected.
I've seen both terms be used almost interchangeably in various online explanations, and most text books I've consulted are also not entirely clear about the distinction.
Is there perhaps a clear and simple way of explaining the difference that you guys know of?
Type conversion (also sometimes known as type cast)
To use a value of one type in a context that expects another.
Nonconverting type cast (sometimes known as type pun)
A change that does not alter the underlying bits.
Coercion
Process by which a compiler automatically converts a value of one type into a value of another type when that second type is required by the surrounding context.
Type Conversion:
The word conversion refers to either implicitly or explicitly changing a value from one data type to another, e.g. a 16-bit integer to a 32-bit integer.
The word coercion is used to denote an implicit conversion.
The word cast typically refers to an explicit type conversion (as opposed to an implicit conversion), regardless of whether this is a re-interpretation of a bit-pattern or a real conversion.
So, coercion is implicit, cast is explicit, and conversion is any of them.
Few examples (from the same source) :
Coercion (implicit):
double d;
int i;
if (d > i) d = i;
Cast (explicit):
double da = 3.3;
double db = 3.3;
double dc = 3.4;
int result = (int)da + (int)db + (int)dc; //result == 9
Usages vary, as you note.
My personal usages are:
A "cast" is the usage of a cast operator. A cast operator instructs the compiler that either (1) this expression is not known to be of the given type, but I promise you that the value will be of that type at runtime; the compiler is to treat the expression as being of the given type, and the runtime will produce an error if it is not, or (2) the expression is of a different type entirely, but there is a well-known way to associate instances of the expression's type with instances of the cast-to type. The compiler is instructed to generate code that performs the conversion. The attentive reader will note that these are opposites, which I think is a neat trick.
A "conversion" is an operation by which a value of one type is treated as a value of another type -- usually a different type, though an "identity conversion" is still a conversion, technically speaking. The conversion may be "representation changing", like int to double, or it might be "representation preserving" like string to object. Conversions may be "implicit", which do not require a cast, or "explicit", which do require a cast.
A "coercion" is a representation-changing implicit conversion.
Casting is the process by which you treat an object type as another type, Coercing is converting one object to another.
Note that in the former process there is no conversion involved, you have a type that you would like to treat as another, say for example, you have 3 different objects that inherit from a base type, and you have a method that will take that base type, at any point, if you know the specific child type, you can CAST it to what it is and use all the specific methods and properties of that object and that will not create a new instance of the object.
On the other hand, coercing implies the creation of a new object in memory of the new type and then the original type would be copied over to the new one, leaving both objects in memory (until the Garbage Collectors takes either away, or both).
As an example consider the following code:
class baseClass {}
class childClass : baseClass {}
class otherClass {}
public void doSomethingWithBase(baseClass item) {}
public void mainMethod()
{
var obj1 = new baseClass();
var obj2 = new childClass();
var obj3 = new otherClass();
doSomethingWithBase(obj1); //not a problem, obj1 is already of type baseClass
doSomethingWithBase(obj2); //not a problem, obj2 is implicitly casted to baseClass
doSomethingWithBase(obj3); //won't compile without additional code
}
obj1 is passed without any casting or coercing (conversion) because it's already of the same type baseClass
obj2 is implicitly casted to base, meaning there's no creation of a new object because obj2 can already be baseClass
obj3 needs to be converted somehow to base, you'll need to provide your own method to convert from otherClass to baseClass, which will involve creating a new object of type baseClass and filling it by copying the data from obj3.
A good example is the Convert C# class where it provides custom code to convert among different types.
According to Wikipedia,
In computer science, type conversion, type casting, type coercion, and type juggling are different ways of changing an expression from one data type to another.
The difference between type casting and type coercion is as follows:
TYPE CASTING | TYPE COERCION
|
1. Explicit i.e., done by user | 1. Implicit i.e., done by the compiler
|
2. Types: | 2. Type:
Static (done at compile time) | Widening (conversion to higher data
| type)
Dynamic (done at run time) | Narrowing (conversion to lower data
| type)
|
3. Casting never changes the | 3. Coercion can result in representation
the actual type of object | as well as type change.
nor representation. |
Note: Casting is not conversion. It is just the process by which we treat an object type as another type. Therefore, the actual type of object, as well as the representation, is not changed during casting.
I agree with #PedroC88's words:
On the other hand, coercing implies the creation of a new object in
memory of the new type and then the original type would be copied over
to the new one, leaving both objects in memory (until the Garbage
Collectors takes either away, or both).
Casting preserves the type of objects. Coercion does not.
Coercion is taking the value of a type that is NOT assignment compatible and converting to a type that is assignment compatible. Here I perform a coercion because Int32 does NOT inherit from Int64...so it's NOT assignment compatible. This is a widening coercion (no data lost). A widening coercion is a.k.a. an implicit conversion. A Coercion performs a conversion.
void Main()
{
System.Int32 a = 100;
System.Int64 b = a;
b.GetType();//The type is System.Int64.
}
Casting allows you to treat a type as if it were of a different type while also preserving the type.
void Main()
{
Derived d = new Derived();
Base bb = d;
//b.N();//INVALID. Calls to the type Derived are not possible because bb is of type Base
bb.GetType();//The type is Derived. bb is still of type Derived despite not being able to call members of Test
}
class Base
{
public void M() {}
}
class Derived: Base
{
public void N() {}
}
Source: The Common Language Infrastructure Annotated Standard by James S. Miller
Now what's odd is that Microsoft's documentation on Casting does not align with the ecma-335 specification definition of Casting.
Explicit conversions (casts): Explicit conversions require a cast
operator. Casting is required when information might be lost in the
conversion, or when the conversion might not succeed for other
reasons. Typical examples include numeric conversion to a type that
has less precision or a smaller range, and conversion of a base-class
instance to a derived class.
...This sounds like Coercions not Casting.
For example,
object o = 1;
int i = (int)o;//Explicit conversions require a cast operator
i.GetType();//The type has been explicitly converted to System.Int32. Object type is not preserved. This meets the definition of Coercion not casting.
Who knows? Maybe Microsoft is checking if anybody reads this stuff.
From the CLI standard:
I.8.3.2 Coercion
Sometimes it is desirable to take a value of a type that is not assignable-to a location, and convert
the value to a type that is assignable-to the type of the location. This is accomplished through
coercion of the value. Coercion takes a value of a particular type and a desired type and attempts
to create a value of the desired type that has equivalent meaning to the original value. Coercion
can result in representation change as well as type change; hence coercion does not necessarily
preserve object identity.
There are two kinds of coercion: widening, which never loses information, and narrowing, in
which information might be lost. An example of a widening coercion would be coercing a value
that is a 32-bit signed integer to a value that is a 64-bit signed integer. An example of a
narrowing coercion is the reverse: coercing a 64-bit signed integer to a 32-bit signed integer.
Programming languages often implement widening coercions as implicit conversions, whereas
narrowing coercions usually require an explicit conversion.
Some coercion is built directly into the VES operations on the built-in types (see §I.12.1). All
other coercion shall be explicitly requested. For the built-in types, the CTS provides operations
to perform widening coercions with no runtime checks and narrowing coercions with runtime
checks or truncation, according to the operation semantics.
I.8.3.3 Casting
Since a value can be of more than one type, a use of the value needs to clearly identify which of
its types is being used. Since values are read from locations that are typed, the type of the value
which is used is the type of the location from which the value was read. If a different type is to
be used, the value is cast to one of its other types. Casting is usually a compile time operation,
but if the compiler cannot statically know that the value is of the target type, a runtime cast check
is done. Unlike coercion, a cast never changes the actual type of an object nor does it change the
representation. Casting preserves the identity of objects.
For example, a runtime check might be needed when casting a value read from a location that is
typed as holding a value of a particular interface. Since an interface is an incomplete description
of the value, casting that value to be of a different interface type will usually result in a runtime
cast check.
Below is a posting from the following article:
The difference between coercion and casting is often neglected. I can see why; many languages have the same (or similar) syntax and terminology for both operations. Some languages may even refer to any conversion as “casting,” but the following explanation refers to concepts in the CTS.
If you are trying to assign a value of some type to a location of a different type, you can generate a value of the new type that has a similar meaning to the original. This is coercion. Coercion lets you use the new type by creating a new value that in some way resembles the original. Some coercions may discard data (e.g. converting the int 0x12345678 to the short 0x5678), while others may not (e.g. converting the int 0x00000008 to the short 0x0008, or the long 0x0000000000000008).
Recall that values can have multiple types. If your situation is slightly different, and you only want to select a different one of the value’s types, casting is the tool for the job. Casting simply indicates that you wish to operate on a particular type that a value includes.
The difference at the code level varies from C# to IL. In C#, both casting and coercion look fairly similar:
static void ChangeTypes(int number, System.IO.Stream stream)
{
long longNumber = number;
short shortNumber = (short)number;
IDisposable disposableStream = stream;
System.IO.FileStream fileStream = (System.IO.FileStream)stream;
}
At the IL level they are quite different:
ldarg.0
conv.i8
stloc.0
ldarg.0
conv.i2
stloc.1
ldarg.1
stloc.2
ldarg.1
castclass [mscorlib]System.IO.FileStream
stloc.3
As for the logical level, there are some important differences. What’s most important to remember is that coercion creates a new value, while casting does not. The identity of the original value and the value after casting are the same, while the identity of a coerced value differs from the original value; coersion creates a new, distinct instance, while casting does not. A corollary is that the result of casting and the original will always be equivalent (both in identity and equality), but a coerced value may or may not be equal to the original, and never shares the original identity.
It’s easy to see the implications of coercion in the examples above, as the numeric types are always copied by value. Things get a bit trickier when you’re working with reference types.
class Name : Tuple<string, string>
{
public Name(string first, string last)
: base(first, last)
{
}
public static implicit operator string[](Name name)
{
return new string[] { name.Item1, name.Item2 };
}
}
In the example below, one conversion is a cast, while the other is a coercion.
Tuple<string, string> tuple = name;
string[] strings = name;
After these conversions, tuple and name are equal, but strings is not equal to either of them. You could make the situation slightly better (or slightly more confusing) by implementing Equals() and operator ==() on the Name class to compare a Name and a string[]. These operators would “fix” the comparison issue, but you would still have two separate instances; any modification to strings would not be reflected in name or tuple, while changes to either one of name or tuple would be reflected in name and tuple, but not in strings.
Although the example above was meant to illustrate some differences between casting and coercion, it also serves as a great example of why you should be extremely cautious about using conversion operators with reference types in C#.
I am little bit confused in boxing and unboxing. According to its definition
Boxing is implicit conversion of ValueTypes to Reference Types (Object).
UnBoxing is explicit conversion of Reference Types (Object) to its equivalent ValueTypes.
the best example for describing this is
int i = 123; object o = i; // boxing
and
o = 123; i = (int)o; // unboxing
But my question is that whether int is value type and string is reference type so
int i = 123; string s = i.ToString();
and
s = "123"; i = (int)s;
Is this an example of boxing and unboxing or not???
Calling ToString is not boxing. It creates a new string that just happens to contain the textual representation of your int.
When calling (object)1 this creates a new instance on the heap that contains an int. But it's still an int. (You can verify that with o.GetType())
String can't be converted with a cast to int. So your code will not compile.
If you first cast your string to object your code will compile but fail at runtime, since your object is no boxed int. You can only unbox an value type into the exactly correct type(or the associated nullable).
Two examples:
Broken:
object o=i.ToString();// o is a string
int i2=(int)o;//Exception, since o is no int
Working:
object o=i;// o is a boxed int
int i2=(int)o;//works
int i = 2;
string s = i.ToString();
This is NOT boxing. This is simply a method call to Int32.ToString() which returns a formatted string representing the value of the int.
i = (int)s;
This code will not compile as there is no explicit conversion defined between System.String and System.Int32.
Think of it in the following way to understand what is and what is not boxing and unboxing:
Boxing: Its when you take a value type and just "stick" it in a reference variable. There is no need of any type specific conversion logic for this operation to work. The variable type will still be the same if you use GetType().
Unboxing: Its just the opposite operation. Take a value type stuck in a reference object and assign it to a value type variable. Again there is no need for any type specific conversion logic for this operation to work.
So if (int)s were valid, it would simply be a explicit conversion and not a unboxing operation, becuase s.GetType() would return System.String, not System.Int32.
Boxing/Unboxing: Conversion of Value Types to its object representation and vice versa (e.g. int and object).
The ToString() method in contrast is an operation which generated a new string, is has nothing to do with boxing/cast/type conversation.
Late to the party on this, but...... I don't like simply reading answers and without proofs behind them. I like to understand the problem and analyse the possible solution and see if it ties in with my understanding. This copy and paste text from the rightly acclaimed excellent 'CLR via C#' by the god Jeff Richter explains this:
Even though unboxed value types don’t have a type object pointer, you can still call virtual methods (such as Equals, GetHashCode, or ToString) inherited or overridden by the type. If your value type overrides one of these virtual methods, then the CLR can invoke the method nonvirtually because value types are implicitly sealed and cannot have any types derived from them. In addition, the value type instance being used to invoke the virtual method is not boxed. However, if your override of the virtual method calls into the base type's implementation of the method, then the value type instance does get boxed when calling the base type's implementation so that a reference to a heap object get passed to the this pointer into the base method. However, calling a nonvirtual inherited method (such as GetType or MemberwiseClone) always requires the value type to be boxed because these methods are defined by System.Object, so the methods expect the this argument to be a pointer that refers to an object on the heap.
Mr Richter should be given a medal for this book. If you haven't got it, get it!! Then you'll get it :)