Tricky Inheritance-Related Architecture - c#

I'm trying to design a system in C# for different character types in a video game. I have a simple inheritance tree for my character types with a Humanoid base class that has several derived classes such as Human, Alien, etc. Each of these character types includes a body with several parts. Currently these parts are stored in an instance of a Body class and each part is described by an instance of BodyPart class.
The main complication comes when I want to have derived classes for BodyPart since each character type's body parts will have some additional specific properties. The main reason I want the BodyPart instances to be grouped in a Body class is so that I can use an indexer since I need to able to iterate over them and still be able to use dot notation to access specific parts easily.
The following pseudocode should give you an idea of what I'm trying to achieve and how I have already tried to implement it.
public class BodyPart
{
public float health;
//...
}
public class HumanBodyPart : BodyPart
{
public float exampleHumanStuff;
//.. human specific stuff
}
public class AlienBodyPart : BodyPart
{
public float exampleAlienStuff;
//.. alien specific stuff
}
public class Humanoid
{
public class Body<T> where T : BodyPart
{
public T head;
public T leftArm;
public T rightArm;
//...
public T this[int i]
{
get
{
switch (i)
{
case 0:
return head;
case 1:
return leftArm;
//...
}
}
}
}
public virtual Body<BodyPart> body { get; }
public void Example {
body.head.health = 50;
body[2].health = 55;
}
}
public class Human : Humanoid
{
public Body<HumanBodyPart> humanBody;
public override Body<BodyPart> body { get { return (Body<BodyPart>)humanBody; } }
public void Example
{
body.rightArm.exampleHumanStuff = 5;
}
}
public class Alien : Humanoid
{
public Body<AlienBodyPart> alienBody;
public override Body<BodyPart> body { get { return (Body<BodyPart>)alienBody; } }
public void Example
{
body.leftArm.exampleAlienStuff = 5;
}
}
The dead end with this approach is that the Body class is not contravariant (I think?) so casting a Body<HumanBodyPart> to Body<BodyPart> won't work. But I can't figure out another way to access the Body<HumanBodyPart> class instance in Human from the base Humanoid class so that in the base class it's treated as a Body<BodyPart>. Is there a better way of doing this?

You can make Humanoid generic of BodyPart itself:
public class Humanoid<T> where T : BodyPart
{
public class Body
{
public T head;
//...
public T this[int i]
{
get
{
switch (i)
{
case 0:
return head;
//...
}
return default;
}
}
}
public Body body { get; }
public void Example()
{
body.head.health = 50;
body [2].health = 55;
}
}
public class Human : Humanoid<HumanBodyPart>
{
public void Example()
{
body.rightArm.exampleHumanStuff = 5;
}
}
public class Alien : Humanoid<AlienBodyPart>
{
public void Example()
{
body.leftArm.exampleAlienStuff = 5;
}
}
Also this class hierarchy does not support all possible use-cases (for example collection of different Humanoid's, but you can workaround some with non-generic interfaces (for Humanoid and Body)).
As for variance it is supported only for interfaces and delegates (and arrays, but don't use it) in C#. In your case something like this will work:
public interface IBody<out TInner>
{
public TInner head { get; }
public TInner leftArm { get; }
public TInner this[int i] { get; }
}
IBody<HumanBodyPart> humanBody = ...;
IBody<BodyPart> body = humanBody;

I assume you want to assign a specific BodyPart of the Humanoid class. I would use this:
public class Humanoid <T> where T : BodyPart
{
public class Body<T>
{....
And in the end when you describing a Human you can use:
public class Human : Humanoid <HumanBodyPart>
{.......

Related

(c#) How can Initialize a generic type with it's type argument object through it's non-generic base class with type safety

I have an ability data factory which has a generic function for creating specific types of abilities. The abilities themselves need to have their own unique AbilityData object passed in which contains both unique and common immutable settings of the ability. The factory contains has the list of this data, which it uses to initialize the abilities upon creation.
My problem is that the solution I have is not type safe. The ability essentially has to validate that the data belongs to it and the factory passes it in. I want to know if there's a type safe way of achieving this, since it feels like a work around solution and maybe a code smell.
public class AbilityFactory : MonoBehaviour
{
[SerializeField]
private List<AbilityData> abilityData;
public IReadOnlyList<AbilityData> AbilityData => abilityData;
public int AbilityCount => abilityData.Count;
public Tability CreateAbility<Tability>() where Tability : Ability
{
Tability instance = Activator.CreateInstance<Tability>();
for (int i = 0; i < AbilityData.Count; i++)
{
if(instance.MatchAbilityData(AbilityData[i]))
{
instance.Initialize(AbilityData[i]);
}
}
return instance;
}
}
public abstract class Ability
{
protected int level;
public abstract bool MatchAbilityData(AbilityData abilityData);
public abstract void Initialize<TabilityData>(TabilityData data) where TabilityData : AbilityData;
public void IncreaseLevel()
{
level++;
}
public void Update()
{
OnUpdate();
}
protected virtual void OnUpdate()
{
}
}
public abstract class Ability<T> : Ability where T : AbilityData
{
public T Data { get; private set; }
public sealed override void Initialize<TabilityData>(TabilityData data)
{
this.Data = data as T;
}
public sealed override bool MatchAbilityData(AbilityData abilityData)
{
return abilityData is T;
}
}

Handling the interacton of intances of classes belong to two parallel inhertiance groups

I have two groups of classes in my code and one group has logic and other group has data and inheritance is also being used in each group. I tried to mimic the situation which I am dealing with in below code snippet. The problem I have is how to handle the objects of derived data classes efficiently in related instances of logic classes. Right now I am trying to cast the instance of derived data class in a method of derived logic class which I do not think is logical. I need some guidance to address this issue.
void Main()
{
var item1 = new D1();
var holder1 = new DataHolder1() { localProp1 = "test" };
var holderout = item1.Method1(holder1);
holderout.Dump();
}
public class BaseDataHolder
{
public string prop { get; set; }
}
public class DataHolder1 : BaseDataHolder
{
public string localProp1 { get; set; }
}
public class DataHolder2 : BaseDataHolder
{
public string localProp2 { get; set; }
}
public class BaseClass
{
public virtual BaseDataHolder Method1(BaseDataHolder holder)
{
return null;
}
}
public class D1 : BaseClass
{
public override BaseDataHolder Method1(BaseDataHolder holder)
{
(holder as DataHolder1).localProp1.Dump();
(holder as DataHolder1).localProp1 = "change1";
return holder;
}
}
public class D2 : BaseClass
{
public override BaseDataHolder Method1(BaseDataHolder holder)
{
(holder as DataHolder2).localProp2.Dump();
(holder as DataHolder2).localProp2 = "change2";
return holder;
}
}
I don't see why it would be illogical since looks like you are trying to get DataHolder1 always in class D1. Rather, why can't your class compose with Data class instance and use that in method like
public class D1 : BaseClass
{
private readonly DataHolder1 holder;
public D1(DataHolder1 holder) { this.holder = holder; }
public override BaseDataHolder Method1()
{
holder.localProp1.Dump();
holder.localProp1 = "change1";
return holder;
}
}
Then you can just say
var item1 = new D1(new DataHolder1());
BaseDataHolder data = item1.Method1();
This violates the Liskov substitution principle. In summary, it's bad, because your signature promises to work well with any BaseDataHolder but in reality it will just crash if the wrong BaseDataHolder is passed in.
I cannot really give a solution because we don't know your requirements. From what you have posted, your three logic classes should drop the inheritance and just have three different method signatures, each telling what it needs instead of all of them lying about what they need and then crashing randomly.

How to pass a polymorphic object as a derived one?

to keep things simple I have two classes: ActionTaken and MovementTaken. MovementTaken is a derived class from ActionTaken. I have a Queue full of actions, and each action has a char that determines the type of action. (Every action has a correct type) I want to pass elements of the Queue to a function, that works specifically with a MovementTaken parameter, but since I'm using polymorphism the parameter is of type ActionTaken, but then I cannot use member variables from MovementTaken, but don't exist in ActionTaken. But if I set the function activateMovement's parameter to type MovementTaken, I believe there would be an error, saying you cannot convert a base type to a derived type. Here's the code:
public abstract class ActionTaken : MonoBehaviour
{
public char type;
public Transform minionTakingAction;
}
public class MovementTaken : ActionTaken
{
public int targetTileH;
public int targetTileV;
public MovementTaken(Transform _minionTakingAction, int _targetTileH, int _targetTileV)
{
type = 'M';
minionTakingAction = _minionTakingAction;
targetTileH = _targetTileH;
targetTileV = _targetTileV;
}
}
Queue<ActionTaken> actionTaken;
public void activateMovement(ActionTaken toActivate)
{//some code using toActivate's members targetTileH and targetTileV}
If you know the argument passed to the method is a MovementTaken instance, you can just downcast it:
public void activateMovement(ActionTaken toActivate)
{
MovementTaken casted = toActivate as MovementTaken;
// Do something with casted.targetTileH and/or caster.targetTileV
The advantage of Abstract classes is defining base implementation, or to force derived types into implementation details:
public abstract class ActionTaken : MonoBehaviour
{
public char Type { get; protected set; }
public Transform Target { get; }
// base ctor
protected ActionTaken(Transform target)
{
Type = '\0';
Target = target;
}
// Force implementation onto sub class
public abstract void Activate();
}
public class MovementTaken : ActionTaken
{
public int TileH { get; set; }
public int TileV { get; set; }
public MovementTaken(Transform target, int tileH, int tileV)
: base(target)
{
Type = 'M';
TileH = tileH;
TileV = tileV;
}
public override void Activate()
{
//some code using TileH and TileV
}
}
Therefore your calling code would be:
Queue<ActionTaken> actionTaken;
public void activateMovement(ActionTaken action)
{
action.Activate();
}
I'm also not sure what Type is being used for, but if you still need it, it might be better off as a constant defined in each class that derives from ActionTaken if you have more.
This can make sense if you end up filling your Queue<ActionTaken> with various derived movement types. Otherwise your ActivateMovement method could end up being a long switch statement.
An interface also might be advantageous here:
public interface IActionTaken
{
Transform Target { get; }
void Activate();
}
Which you would then replace your queue: Queue<IActionTaken> Actions
The code for invoking all of the actions in the queue could then be extremely straightforward:
while(Actions.Count > 0)
{
IActionTaken current = Actions.Dequeue();
current.Activate();
}

Casting to a generic interface [duplicate]

I have the following classes
public abstract class BaseViewPresenter { }
public abstract class BaseView<T> : UserControl
where T : BaseViewPresenter { }
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter> { }
I have a method that looks like this (simplified)
public BaseView<BaseViewPresenter> Resolve(BaseViewPresenter model)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
// Correctly creates BaseView object
var control = Activator.CreateInstance(viewType);
// Fails to cast as BaseView<BaseViewPresenter> so returns null
return control as BaseView<BaseViewPresenter>;
}
When I call this using an instances of LoginPresenter
var login = new LoginPresenter();
var ctl = Resolve(login);
The line Activator.CreateInstance(viewType) correctly resolves into a new instances of my LoginView, however control as BaseView<BaseViewPresenter> can't do the cast correctly so returns null.
Is there a way to correctly cast the control into BaseView<BaseViewPresenter> without using specific type generics?
Since LoginView inherits from BaseView<LoginPresenter>, and LoginPresenter inherits from BaseViewPresenter, I would assume there's a way to convert LoginView to BaseView<BaseViewPresenter>.
I am stuck with using .Net 3.5
This is a very frequently asked question. Let's rename your types:
abstract class Fruit { } // was BaseViewPresenter
abstract class FruitBowl<T> where T : Fruit // was BaseView
class Apple : Fruit { } // was LoginPresenter
class BowlOfApples : FruitBowl<Apple> { } // was LoginView
Your question now is:
I have a BowlOfApples, which inherits from FruitBowl<Apple>. Why can I not use it as a FruitBowl<Fruit>? An apple is a fruit, so a bowl of apples is a bowl of fruit.
No, it isn't. You can put a banana in a bowl of fruit, but you can't put a banana in a bowl of apples, and therefore a bowl of apples is not a bowl of fruit. (And by similar argument, a bowl of fruit is not a bowl of apples either.) Since the operations you can legally perform on the two types are different, they cannot be compatible.
Here is a photo of StackOverflow legend Jon Skeet demonstrating this fact:
The feature you want is called generic contravariance, and it is supported only on interfaces and delegate types when the compiler can prove that the variance is safe, and when the varying type is a reference type. For example, you can use an IEnumerable<Apple> in a context where IEnumerable<Fruit> is needed because the compiler can verify that there is no way that you can put a Banana into a sequence of fruit.
Do a search on "C# covariance and contravariance" on this site or on the web and you'll find many more details about how this feature works. In particular, my series of articles on how we designed and implemented this feature in C# 4 starts here: http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx
I accepted Eric's answer since it provides a great explanation of why what I wanted wasn't possible, but I also thought I'd share my solution in case anyone else runs into this same problem.
I removed the generic type parameter from my original BaseView class, and created a 2nd version of the BaseView class that included the generic type parameter and specifics for it.
The first version is used by my .Resolve() method or other code that doesn't care about the specific types, and the second version is used by any code that does care, such as the implentation of a BaseView
Here's an example of how my code ended up looking
// base classes
public abstract class BaseViewPresenter { }
public abstract class BaseView : UserControl
{
public BaseViewPresenter Presenter { get; set; }
}
public abstract class BaseView<T> : BaseView
where T : BaseViewPresenter
{
public new T Presenter
{
get { return base.Presenter as T; }
set { base.Presenter = value; }
}
}
// specific classes
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter>
{
// Can now call things like Presenter.LoginPresenterMethod()
}
// updated .Resolve method used for obtaining UI object
public BaseView Resolve(BaseViewPresenter presenter)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
BaseView view = Activator.CreateInstance(viewType) as BaseView;
view.Presenter = presenter;
return view;
}
You're expecting to treat the type as being covariant with respect to the generic argument. Classes can never be covariant; you'd need to use an interface rather than (or in addition to) an abstract class to make it covariant with respect to T. You'd also need to be using C# 4.0.
My usual solution to this problem is to create an intermediary class that has access to the type-parametric class's methods through delegates. Fields can also be accessed through getters/setters.
The general pattern goes:
public abstract class Super {}
public abstract class MyAbstractType<T> where T : Super {
public MyGeneralType AsGeneralType() {
return MyGeneralType.Create(this);
}
// Depending on the context, an implicit cast operator might make things
// look nicer, though it might be too subtle to some tastes.
public static implicit operator MyGeneralType(MyAbstractType<T> t) {
return MyGeneralType.Create(t);
}
public int field;
public void MyMethod1() {}
public void MyMethod2(int argument) {}
public abstract bool MyMethod3(string argument);
}
public delegate T Getter<T>();
public delegate void Setter<T>(T value);
public delegate void MyMethod1Del();
public delegate void MyMethod2Del(int argument);
public delegate bool MyMethod3Del(string argument);
public class MyGeneralType {
public Getter<int> FieldGetter;
public Setter<int> FieldSetter;
public MyMethod1Del MyMethod1;
public MyMethod2Del MyMethod2;
public MyMethod3Del MyMethod3;
public static MyGeneralType Create<T>(MyAbstractType<T> t) where T : Super {
var g = new MyGeneralType();
g.FieldGetter = delegate { return t.field; };
g.FieldSetter = value => { t.field = value; };
g.MyMethod1 = t.MyMethod1;
g.MyMethod2 = t.MyMethod2;
g.MyMethod3 = t.MyMethod3;
return g;
}
public int field {
get { return FieldGetter(); }
set { FieldSetter(value); }
}
}
The above exemplifies getting all the methods and fields but normally I only need a few of them. This is a general solution to the problem and one could feasibly write a tool to generate these intermediary classes automatically, which I might at some point.
Try it here: https://dotnetfiddle.net/tLkmgR
Note that this is enough for all my cases, but you can be extra hacky with this:
public abstract class MyAbstractType<T> where T : Super {
// ... Same everything else ...
// data fields must become abstract getters/setters, unfortunate
public abstract int field {
get;
set;
}
public static implicit operator MyAbstractType<Super>(MyAbstractType<T> t) {
return MyGeneralType.Create(t);
}
}
public class MyGeneralType : MyAbstractType<Super> {
// ... same constructors and setter/getter
// fields but only keep method fields
// that contain the method references for
// implementations of abstract classes,
// and rename them not to clash with the
// actual method names ...
public MyMethod3Del myMethod3Ref;
// Implement abstract methods by calling the corresponding
// method references.
public override bool MyMethod3(string argument) {
return myMethod3Ref(argument);
}
// Same getters/setters but with override keyword
public override int field {
get { return FieldGetter(); }
set { FieldSetter(value); }
}
}
And there you go, now you can literally cast a MyAbstractType<Sub> where Sub : Super to a MyAbstractType<Super>, although it's no longer the same object anymore, but it does retain the same methods and data, it's sort of a complex pointer.
public class Sub : Super {}
public class MySubType : MyAbstractType<Sub> {
public int _field;
public override int field {
get { return _field; }
set { _field = value; }
}
public override bool MyMethod3(string argument) {
Console.WriteLine("hello " + argument);
return argument == "world";
}
}
public class MainClass {
public static void Main() {
MyAbstractType<Sub> sub = new MyAbstractType<Sub>();
MyAbstractType<Super> super = sub;
super.MyMethod3("hello"); // calls sub.MyMethod3();
super.field = 10; // sets sub.field
}
}
This isn't as good in my opinion, the other version of MyGeneralType is a more straighforward layer over the concrete types, plus it doesn't require rewriting the data fields, but it does actually answer the question, technically. Try it here: https://dotnetfiddle.net/S3r3ke
Example
Using these abstract classes:
public abstract class Animal {
public string name;
public Animal(string name) {
this.name = name;
}
public abstract string Sound();
}
public abstract class AnimalHouse<T> where T : Animal {
List<T> animals;
public AnimalHouse(T[] animals) {
this.animals = animals.ToList();
}
public static implicit operator GeneralAnimalHouse(AnimalHouse<T> house) {
return GeneralAnimalHouse.Create(house);
}
public List<string> HouseSounds() {
return animals.Select(animal => animal.Sound()).ToList();
}
}
We make this "general" variant:
public delegate List<string> HouseSoundsDel();
public class GeneralAnimalHouse {
public HouseSoundsDel HouseSounds;
public static GeneralAnimalHouse Create<T>(AnimalHouse<T> house) where T : Animal {
var general = new GeneralAnimalHouse();
general.HouseSounds = house.HouseSounds;
return general;
}
}
And finally with these inheritors:
public class Dog : Animal {
public Dog(string name) : base(name) {}
public override string Sound() {
return name + ": woof";
}
}
public class Cat : Animal {
public Cat(string name) : base(name) {}
public override string Sound() {
return name + ": meow";
}
}
public class DogHouse : AnimalHouse<Dog> {
public DogHouse(params Dog[] dogs) : base(dogs) {}
}
public class CatHouse : AnimalHouse<Cat> {
public CatHouse(params Cat[] cats) : base(cats) {}
}
We use it like this:
public class AnimalCity {
List<GeneralAnimalHouse> houses;
public AnimalCity(params GeneralAnimalHouse[] houses) {
this.houses = houses.ToList();
}
public List<string> CitySounds() {
var random = new Random();
return houses.SelectMany(house => house.HouseSounds())
.OrderBy(x => random.Next())
.ToList();
}
}
public class MainClass {
public static void Main() {
var fluffy = new Cat("Fluffy");
var miu = new Cat("Miu");
var snuffles = new Cat("Snuffles");
var snoopy = new Dog("Snoopy");
var marley = new Dog("Marley");
var megan = new Dog("Megan");
var catHouse = new CatHouse(fluffy, miu, snuffles);
var dogHouse = new DogHouse(snoopy, marley, megan);
var animalCity = new AnimalCity(catHouse, dogHouse);
foreach (var sound in animalCity.CitySounds()) {
Console.WriteLine(sound);
}
}
}
Output:
Miu: meow
Snoopy: woof
Snuffles: meow
Fluffy: meow
Marley: woof
Megan: woof
Notes:
I added names so it's clear that the method references carry their owner's data with them, for those unfamiliar with delegates.
The required using statements for this code are System, System.Collections.Generic, and System.Linq.
You can try it here: https://dotnetfiddle.net/6qkHL3#
A version that makes GeneralAnimalHouse a subclass of AnimalHouse<Animal> can be found here: https://dotnetfiddle.net/XS0ljg

Mapping classes c#

I am writing a tranformer that takes some input and gives an output.I need to call a specific tranformer based on my input type.
public static myentrypoint( template t);
{
//I could do something like this.
switch(t)
{
case t1:
transformt1(..);
case t2:
transformt1(..);
....
}
}
Trasform1 : Itransform
{
tranform1(...);
}
Trasform2 : Itransform
{
tranform2(...);
}
I need to map which function to call based on what my template is. I can do a switch but are there more cleaner ways to do this using some design patterns ? I was thinking a of writing a static dictionary. I am new to OOP so any suggestions would be great.
If template is a class, and each template potentially has a different transform, then why not just include the transform function inside of your template class?
public static myentrypoint( ITemplate t);
{
t.transform();
}
The way that I do these types of situations is through the use of Generics. (Shameless self-promotion of a blog post)
Basically, you'll have your base class set up like this:
public abstract class Transformer<T>
where T : Template
{
public abstract void Transform(T item);
}
Then you derive for each of your types like this:
public class Transformer1 : Tansformer<Template1>
{
public void Transform(Template1 item)
{
}
}
public class Transformer2 : Transformer<Template2>
{
public void Transform(Template2 item)
{
}
}
Then you'll just need a factory to give you the correct Transformer.
public class TransformFactory
{
public Transformer<T> GetTransformer<T>(T item)
{
if (item is Template1)
return new Transformer1();
else if (item is Template2)
return new Transformer2();
// ...
}
}
The benefit of this approach is that you'll be able to encapsulate all behavior on that specific type in the concrete implementations. If there is any common behavior on them all, you can do that in the abstract base.
Invoking methods based on a parameter without switch-case statements in C#
In OOP, based on the [open/close principle] which says that software entities such as classes and functions should be open for extension, but closed
for modification.
Methods which use switch-case statement would call this principle into question. In order to implement this principle inside the codes without
causing changes in their functionality.
We use a pattern named "Delegate Dictionary Pattern".
For example, we have an entity named Template that keep input values as well as some of Transform classes for processing this Template.
Template class for keeping input value
public class Template
{
public int TransformNo { get; set; }
public string Title { get; set; }
}
ITransform interface for transform abstract
public interface ITransform
{
void Do(Template template);
}
Transform1 as a concrete class of ITransform
public class Transform1 : ITransform
{
public void Do(Template template)
{
Console.WriteLine($"Transform : {template.TransformNo}, TemplateTitle : { template.Title}");
}
}
Transform2 as a concrete class of ITransform
public class Transform2 : ITransform
{
public void Do(Template template)
{
Console.WriteLine($"Transform : {template.TransformNo}, TemplateTitle : { template.Title}");
}
}
TransformCordinator class for coordinating template of *ITransformer**
public class TransformCordinator
{
Dictionary<int, Action<Template>> transformMap = new Dictionary<int, Action<Template>>();
public TransformCordinator()
{
transformMap.Add(1, x => new Transform1().Do(x));
transformMap.Add(2, x => new Transform2().Do(x));
}
public void Do(Template template)
{
transformMap[template.TransformNo](template);
}
}
// example
class Program
{
static void Main(string[] args)
{
var transformCordinator = new TransformCordinator();
transformCordinator.Do(new Template() { TransformNo = 1, Title = "Hi!" });
Console.ReadLine();
}
}

Categories

Resources