Thanks ahead, community!
As the title describes, I would like to cast an object that is in parent type to a child type, which is actually a child type, whilst this 'specific type' cannot be known until runtime.
Lets say I have following data holder:
public class Holder {}
public class Holder<T> : Holder
{
public T Value;
}
And this Holder (not Holder<T>) will be given to some script at runtime.
I need to cast this Holder into Holder<T> (eg, Holder<string>), so that I can access the Value : T.
For now, I can just mannually add casting cases and their coresponding methods to process it, but time by time there will be more types that goes into this Holder<T>, and it would become imposible to manage in this way.
Is there a way to accomplish this objective?
This Holder must not be flattened, as it is being used in a context as below:
public class SomeNode
{
protected Holder holder;
}
public class SomeNode<T> : SomeNode
{
public SomeNode<T>()
{
holder = new Holder<T>();
}
}
I have no clue how to approach this, nor a search keyword to catch a hint about this. Automatic suggestions came up before posting seems not my case, which were:
C# Create (or cast) objects of a specific type at runtime
C# Accessing generic Method without knowing specific type
CodePudding user response:
community! It's a good question. That was interesting. I think this is simple solve for this question. We just need to create a simple constructor like below
public class Holder
{
public string SomeData; // just example data
public Holder()
{
}
public Holder(Holder someData)
{
SomeData = someData.SomeData;
}
}
public class Holder<T> : Holder
{
public T Value;
public Holder(Holder a, T t = default)
:base(a)
{
Value = t;
}
}
public class Programm
{
void Main()
{
var h = new Holder();
var g = new Holder<string>(h);
}
}
CodePudding user response:
If you need to cast to a specific type, you are doing polymorphism wrong. Of course you could do something like this:
switch (holder)
{
case Holder<string> stringHolder:
DoStringThing(stringHolder.Value);
break;
case Holder<int> intHolder:
DoIntThing(intHolder.Value);
break;
...
}
See also: Switch statements with patterns.
However, the idea behind polymorphism is to be able to do things without having to know the specific type. Therefore, re-design the holder classes and have them do the type specific thing themselves:
public abstract class Holder
{
public abstract void DoThing();
}
public abstract class Holder<T> : Holder
{
public abstract T Value { get; }
}
Some examples of specific types:
public class StringHolder : Holder<string>
{
public StringHolder(string value)
{
Value = value;
}
public override string Value { get; }
public override void DoThing()
{
Console.WriteLine($"String of length {Value.Length} is \"{Value}\"");
}
}
public class IntHolder : Holder<int>
{
public IntHolder(int value)
{
Value = value;
}
public override int Value { get; }
public override void DoThing()
{
Console.WriteLine($"The integer {Value} is {(Value % 2 == 0 ? "even", "odd")}");
}
}
Now you can simply write
holder.DoThing();
... without having to cast.