Downcasting is not possible in C#.
A base object is less than a child object, so you cannot create a base object and cast it to a child.
A base class is missing from the properties and methods added in childs, so you cannot create a base object and convert it to be a child object.
It's like saying that a bicycle is a car, and that it has its properties and capabilities.
But upcasting is OOP fundamental: we can say that child is type of base (a car is just an advanced and extended bicycle).
Here you don't want to up or down cast, but create a new instance as formulated in the suggested new title for the question.
So to create another instance of the real base
object type and not a base
you can use reflexion and Activator class.
Example to improve in first intention the code provided
public class Base
{
public string Name;
}
public class Child : Base
{
}
void Go()
{
var a = new Child { Name = "My Name is A" }; // Legal upcast: Child is type of Base
var b = (Child)Test(a);
b.Name = "Sucess";
Console.WriteLine(a.Name);
Console.WriteLine(b.Name);
}
Base Test(Base instance)
{
return (Base)Activator.CreateInstance(instance.GetType());
}
But we can't write:
Base c = new Base();
Child d = (Child)c; // Illegal downcast: Base is not type of Child
Output
My Name is A
Sucess
The use of a generic will be strongly typed and adapted to solve the problem as exposed
void Go()
{
var a = new Child { Name = "My Name is A" };
var b = Test(a);
Console.WriteLine(a.Name);
Console.WriteLine(b.Name);
}
T Test<T>(T instance) where T : Base
{
var instanceNew = Activator.CreateInstance<T>();
instanceNew.Name = "Sucess";
return instanceNew;
}
Because using classes, it can be simplified:
T Test<T>(T instance) where T : Base, new()
{
var instanceNew = new T();
instanceNew.Name = "Sucess";
return instanceNew;
}
But be carefull that this generic solution does not work when passing an object as an ancestor class:
var b = Test((Base)a);
Will be processed as Base
and not Child
.
So we can mix non-generic solution with generic behavior to write:
T Test<T>(T instance) where T : Base, new()
{
var instanceNew = (T)Activator.CreateInstance(instance.GetType());
instanceNew.Name = "Sucess";
return instanceNew;
}
Thus that works better now and it is more consistent:
Base a = new Child { Name = "My Name is A" };
Child b = (Child)Test(a);
Console.WriteLine(a.Name);
Console.WriteLine(b.Name);
Output
My Name is A
Sucess
Possible simplification
Unless you want to do a particular processing in the Test
method, on the real type of the parameter, for a new instance by only knowing this parameter as a type of Base
, to be able to pass any child, and then return it, to refactor some things for example, you can direclty write:
var a = new Child { Name = "My Name is A" };
var b = (Child)Activator.CreateInstance(a.GetType());
b.Name = "Success";
Note: please, don't use base
as a variable name because it is a reserved language keyword, so it does not compile - also, it is an opinion, avoid the use of @base
because it is not clean, and in fact it can be source of problems and confusions.