Imagine having an integer
var aaa = (int)1; -------> here I have an int
var bbb = (object)aaa;-----> bbb is an object but the type is kept...
var ccc = aaa.GetType();---> ... in fact here I still have an integer
now I define a new variable
var ddd = (object)2;
and I want to cast it to the same type as aaa. ccc is a type and it's type integer but I can't do
var ddd = (ccc)2;
So what puzzles me is how to box a 1st variable and then unbox a 2nd variable according to the type of the 1st variable
Obiviously I did it here with int but the matter can be extended to whatever class type.
Thanks in advance
Patrick
CodePudding user response:
You cannot strongly type a variable at runtime. The advantage of a strong type (here int
) versus a week type (object
) is that you know at compile time (or design time) which members an object has and which operations you can apply to it. E.g., you know that you can write 5 * aaa
if aaa
is an int
. You cannot do that with a string
.
aaa.GetType()
yields a System.Type
object at runtime! You cannot use it to cast another object. Well, you could write something like
??? ddd = Convert.ChangeType(bbb, aaa.GetType());
but to what do you want to assign it? The type of ddd
is unknown at compile time and the only possible type you can write in your code is object
again. And btw., ChangeType
returns an object
. What else could it return?
Note that the var
keyword does not help. var
tells the compiler to infer the (strong) static type (which it does of course at compile time). If you hover the mouse over such a variable, the Visual Studio editor will reveal you the concrete type var
stands for.
Generic types are always resolved at compile time. They do not help either.
With a limited number of possible types, you can use a switch expression or switch statement to do appropriate things depending on the type.
string message = bbb switch {
string s => $"bbb is the string '{s}' of length {s.Length}",
int i => $"10 times bbb is {10 * i}",
DateTime d => $"bbb is {d:yyyy-MM-dd HH:mm:ss}",
_ => "bbb has an unexpected type"
};
This uses type test patterns.
With class types this is a bit different. Here you can use Polymorphism. This works in a limited way with value types (structs) if they implement interfaces.
The idea behind polymorphism is that you do not need to know the concrete type of an object to do meaningful things with it. Example:
public abstract class Shape
{
public abstract double Area();
}
public class Square : Shape
{
public double SideLength { get; set; }
public override double Area() => SideLength * SideLength;
}
public class Circle : Shape
{
public double Radius { get; set; }
public override double Area() => Math.PI * Radius * Radius;
}
Given these declarations, you can write:
private static void PrintArea(Shape shape)
{
Console.WriteLine(shape.Area());
}
and
var shapes = new List<Shape> {
new Circle { Radius = 4.5 },
new Square { SideLength = 7.0 }
};
foreach (Shape shape in shapes) {
PrintArea(shape);
}
You do not need to know what kind of shape you have, to determine its area. If you implement new shapes in future, the PrintArea
method and the foreach-loop will not have to be adapted.