C# Inheritance of same class twice - c#

Let's say I've such code
public class Holded
{
protected internal int holdedID = 0;
}
public class Inventory : Holded
{
public Inventory() { }
public void changeHoldedID()
{
this.holdedID = 100;
}
}
public class Equipment : Holded
{
public Equipment() { }
public void writeHoldedID()
{
Console.WriteLine("Holded ID is: {0}!", this.holdedID);
}
}
public class Cargo : Holded
{
public Cargo() { }
}
If I'd call changeHoldedID and then writeHoldedID, console will still output a string like "Holded ID is: 0!". Now what I want to achieve is to have same base class (Holded) in both of classes. So if I'd change holdedID from Inventory, Equipment's writeHoldedID function would output "Holded ID is: 100!". Thanks and regards!
#Edit: More detailed: I have a game. Each person is a character, that owns Equipment, Inventory and Cargo class. Each class contains about 20 slots for "items". Now the thing is, that if you try to move an item, for ex. from inventory, to equipment, and there's such index of item, then the item is "swapped" - goes holded, and now I may throw such holded item into Equipment, Inventory or Cargo. That's why I'm in need to share such class between Eq/Inv/Cargo.

With this inheritance structure, what you are asking is 99.9% impossible.
When you create an Inventory object, you are also creating a Holded object with its own holdedID member. When you create an Equipment object, you get a new Holded object as well, with no relation to the old one. Thus, changes to one objects member won't affect the other, and you want it this way.
*To be clear, you don't get a seperate Holded object when creating a derived class, but it can be helpful to think of it in the way I described it.
I don't know why you want to do what you are asking, but its a pretty good bet you need to rework your understanding of inheritance, objects, and polymorphsim.
Now, I said this was 99.9% impossible. You can mark the base class member static which shares it among all instances of Holded (and derived classes), making your code possible. However, there is almost no chance you actually want to do this. static should only be used when you understand object-oriented design and the consequences of using it.

Have you considered, instead of "is a" inheritance type relationship a "contains a" relationship?
You could do something along the following lines:
public interface IHolded
{
Bar Foo();
}
public class Holded: IHolded { ... }
And now you have two options in how you want to implent Equipment and Inventory:
Directly exposing holded throgh a readonly property:
public class Inventory
{
public Inventory(IHolded holded) { ... }
public IHolded Holded { get; }
}
Having them implement the IHolded interface and delegating
implementation to holded.
public Equipment
{
private readonly IHolded holded;
public Equipment(IHolded holded) { this.holded = holded; }
public Bar Foo() { return holded.Foo() };
}
This way you are injecting a Holded object when creating Equipment and Inventory instances ensuring a consistent state in both instances.

A Dictionary to store the person and their HoldedId might work
public class Holded
{
protected internal static Dictionary<string, int> _personHoldedIDs;
internal string _person;
public Holded(string person)
{
_person = person;
if (_personHoldedIDs == null)
_personHoldedIDs = new Dictionary<string, int>();
if (!_personHoldedIDs.ContainsKey(_person))
_personHoldedIDs.Add(_person, 0);
}
}
public class Inventory : Holded
{
public Inventory(string person) : base(person) { }
public void changeHoldedID()
{
_personHoldedIDs[_person] = 100;
}
}
public class Equipment : Holded
{
public Equipment(string person) : base(person) { }
public void writeHoldedID()
{
Console.WriteLine("Holded ID is: {0}!", _personHoldedIDs[_person]);
}
}

Related

Is it possible in C# to reference an object in another object, when data type is not known at compile time

I'm writing a small game in Unity (C#). I have two classes, e.g. Person and Company.
I have a third class "Objects" which represents stuff of any kind.
An instance of the Obejcts class has to contain a variable "owner", either a Person or a Company.
During runtime the owner must change between Company and Person data type.
I cant just assume that the possessor of the object is the owner, due to game concept.
The following is exemplary code:
public class Person {
public List<Objects> inventory = new List<Objects>();
...
}
public class Company {
public List<Objects> inventory = new List<Objects>();
...
}
public class Objects {
public Person, Company owner; // just exemplary two possible data types
...
}
Im "translating" the code from Python, so this procedure wasn't a problem before but now it is.
In short, i dont want to alter my data in any way, i only want to change the data type of the variable itself (called literal i think) during runtime. Or to "disable" the type checking for this variable.
My "working" solution is to implement two owners variables for Persons and Companies, but its very error prone and i have to write a lot more code to accomplish the same functionality.
Data Type var doesn't work for me because the owner variable has to be public.
Data Type object doesn't work either, because i can't call the methods of class Objects.
I've read about reflection and interfaces, but i dont think that thats what i need tbh.
Dynamic would have been possible, but the Data Type must be changed for multiple times, e.g. Person -> Company -> Person.
Either use an interface
public interface IOwner
{
public List<Objects> inventory { get; }
}
public class Person : IOwner
{
public List<Objects> inventory { get; private set; } = new ();
...
}
public class Company : IOwner
{
public List<Objects> inventory { get; private set; } = new ();
...
}
public class Objects
{
public IOwner Owner;
}
or common base class
public abstract class Owner
{
// shared implementations
public List<Objects> inventory = new();
}
public class Person : Owner
{
...
}
public class Company : Owner
{
...
}
public class Objects
{
public Owner Owner;
}
Alternatively you could use the mother of all types object (= System.Object)
public class Objects
{
public object Owner;
}
or dynamic
public class Objects
{
public dynamic Owner;
}
Depends a bit on whether you really only want to store a reference or actually do something with/through it

Can't cast inherited class field which is a derived class

Before I explain my problem, keep in mind that I went for an architecture like this because this is going to be used in an inventory system under Unity, so I had to separate the Item which is a MonoBehavior which is just something in the world from its Data which are just values used for Inventory purposes... If that makes sense.
I have an architecture that goes like this:
public class ItemData
{
// some fields...
public string _name; //should be private with its properties but it doesn't matter in the current example
}
public class EquipmentData : ItemData
{
// some additional fields...
public float _weight;
}
public class Item
{
private ItemData _data;
//Properties
public virtual ItemData Data { get; set; }
}
public class Equipment : Item
{
//Properties
public override ItemData Data
{
get { return _data as EquipmentData; }
set { _data = value as EquipmentData; }
}
}
So, basically I have an item hierarchy that goes even deeper but 1 level is enough to explain myself. (It keeps going like Weapon : Equipment)...
The thing is, if I leave private ItemData _data; in Item class, and add a private EquipmentData _eData; in Equipment class, I will have the ItemData fields twice since EquipmentData inherits ItemData and so on for the other derived classes... getting it a third time if I have a class that derives from Equipment etc...
Something like:
public class Item
{
private ItemData _data;
}
public class Equipment : item
{
private EquipmentData _eData;
}
The fields of ItemData such as _name will appear twice in Equipment and I don't want that...
So I am guessing there is something wrong with my architecture, and there might be a way around this method that looks kind of "dirty", but I couldn't find anything specific for this problem online and I have reached my limits.
What I have tried:
I have tried using the keyword new in Equipment thinking I could hide the initial protected ItemData _data; that is in my Item class, and then have protected new EquipmentData _data; in Equipment but it obviously does not let me since to Shadow _data it needs to be the same type, doesn't seem to work with derived types.
Also, as shown in my code sample, I have tried overriding the property to return the proper type depending on the class it is called in, the casts always return null...
I still find it strange that I ended up trying to implement something like that, so I am open to new ideas to restructure things in a better way, or if someone has a solution I haven't thought of to keep things that way but make them work, it'd be very nice.
I hope I was detailed enough in my problem, if not I can clear things up if needed.
What You need is Generic Classes. By this, You can assign each Item its proper type of ItemData. So Equipment will have its EquipmentData assigned.
//TItemData is a name of this generic type.
//It could be T for example, just like variable name.
//These type names start from T by convention.
//This is not a new class or something like that.
//where TItemData : ItemData is a constraint,
//that assumes that this type should be a subtype of ItemData
public abstract class Item<TItemData> where TItemData : ItemData
{
protected TItemData Data;
}
//EquipmentData is a subtype of ItemData, so it fits here.
//No chances to write, for example, IntEquipment : Item<int> ,
//because int does not derive from ItemData.
public class Equipment : Item<EquipmentData>
{
//here Data will be of EquipmentData type, without any casting.
}
By implementing the above You will achieve Type Safety.
EDIT
To make a class that properly extends Equipment (let's call it a Weapon), and has its proper ItemData (let's call it WeaponData), You need to write something like this:
Edit Equipment, and make it abstract:
public abstract class Equipment<TEquipmentData>
: Item<TEquipmentData>
//this constraint is VERY important, as EquipmentData derives from ItemData, thus fulfill Item<TItemData> constraint.
where TEquipmentData : EquipmentData
{
//Data will have EquipmentData type here.
}
Create WeaponData
public WeaponData : EquipmentData
{
}
Create Weapon
public class Weapon : Equipment<WeaponData>
{
//Data will have WeaponData type here.
}
This works:
public class OverridePropertiesWithSameField
{
public void Test()
{
ChildItem ci = new ChildItem();
ChildItemData cid = new ChildItemData();
cid.ItemDataProp = "ItemDataProperty"; // Inherited
cid.ChildItemDataProp = "ChildItemDataProp"; // Specific
ci.ItemData = cid;
// You know you need ChildItemData type here.
var childItemData = ci.ItemData as ChildItemData;
string itemDataProp = childItemData.ItemDataProp;
string childItemDataProp = childItemData.ChildItemDataProp;
}
}
public class Item
{
protected ItemData data;
public virtual ItemData ItemData { get; set; }
}
public class ChildItem : Item
{
public override ItemData ItemData
{
get { return base.data; }
set { base.data = value; }
}
}
public class ItemData
{
public string ItemDataProp { get; set; }
}
public class ChildItemData : ItemData
{
public string ChildItemDataProp { get; set; }
}
You can use a generic type parameter, with a generic type constraint (where).
public class Item<DATA> where DATA : ItemData
{
public virtual DATA Data { get; set; }
}
Now your class can use a specific ItemData:
Item<ItemData> has property
public virtual ItemData Data { get; set; }
Item<EquipmentData> has property
public virtual EquipmentData Data { get; set; }
Item<ANOTHER> has property
public virtual ANOTHER Data { get; set; }

Creating a virtual generic method in C#

I have some base classes like this:
public class AbstractData
{
public int ID { get; set; }
}
public class Person: AbstractData
{
public string Name { get; set; }
}
public class AbstractManager<T> where T: AbstractData
{
public virtual List<T> GetAll()
{
}
public virtual T GetOne(int id)
{
}
}
public class PersonManager: AbstractManager<Person>
{
public override List<Person> GetAll()
{
//...
}
public override Person GetOne(int id)
{
//...
}
}
Now, I have a Windows Forms base class, like this:
public class BaseForm: Form
{
public virtual AbstractManager<T> GetManager<T>() where T: AbstractData
{
return null;
}
}
and a derived form:
public class PersonForm: BaseForm
{
public override AbstractManager<T> GetManager<T>()
{
return new PersonManager();
}
}
The problem is, I keep getting compile errors on the PersonForm class:
Cannot implicitly convert type 'PersonManager' to 'AbstractManager<T>'
Is there a way in which I can create this virtual method and have every class derived from BaseForm return the concrete representation of the AbstractManager?
If I get rid of the generic on the AbstractManager class then I compile OK (with a few code changes), but then the GetAll method can't return a List<T>. It would have to return a List<AbstractData> instead, which causes issues in converting from List<Person> to List<AbstractData>.
Any help would be appreciated.
First off all, please never do this:
class C<T>
{
void M<T>(T t) { }
}
Now we have two things named T both in scope and they are different. This is legal but extremely confusing. Choose better names for your type parameters.
Let's simplify your example:
class FruitBasket<T> where T : Fruit { }
class AppleBasket : FruitBasket<Apple> { }
class C
{
public static FruitBasket<T> GetBasket<T>() where T: Fruit
{
return new AppleBasket();
}
}
Now do you see why this is wrong? What if someone calls C.GetBasket<Orange>() and you hand them a basket of apples?
Any help would be appreciated.
What's step one of getting out of a hole? STOP DIGGING.
You have Genericity Happiness Disease, which is common to C# programmers who are discovering the power of the generic type system and then want to use it for everything whether that makes sense or not. Stop trying to capture all the relationships in your business process in the generic type system; that's not what it was designed for.
The test is: can you say "an apple basket is a basket of apples, where apples are a kind of fruit" and have someone who is not a programmer agree with you? Yes. Can you say "a person manager is an abstract manager of persons where person is a kind of abstract data" and have someone who is not a programmer agree with you? No. Then you are not successfully modeling the business domain in the type system. Start over, avoid generics, and try to come up with relationships between types that make sense.
By declaring
public virtual AbstractManager<T> GetManager<T>() where T: AbstractData
in BaseForm, you're promising that every class derived from BaseForm supports GetManager for any type T. For example, if you had another AbstractData subclass named Invoice, then you could write
personForm.GetManager<Invoice>()
and PersonForm would be expected to return an InvoiceManager.
If you want every class derived from BaseForm to support GetManager for only one type T, then move the T type parameter from GetManager to BaseForm:
public class BaseForm<T>: Form where T: AbstractData
{
public virtual AbstractManager<T> GetManager()
{
return null;
}
}
public class PersonForm: BaseForm<Person>
{
public override AbstractManager<Person> GetManager()
{
return new PersonManager();
}
}
UPDATE: Chad Henderson points out that the Windows Forms designer can't handle generic base classes. If that's a problem for you, then you could try an alternate approach:
public interface IForm<T> where T: AbstractData
{
AbstractManager<T> GetManager();
}
public class BaseForm: Form
{
// ... base functionality that doesn't depend on T ...
}
public class PersonForm: BaseForm, IForm<Person>
{
public AbstractManager<Person> GetManager()
{
return new PersonManager();
}
}

Static member inheritance in C#, what is the best way?

What is the best way to solve this?
A static member is one for all subclasses and i want a different static member for subclasses but with the same name so I can use vehicle.canDo; this should give me different arrays depending what class the vechicle instance really is.
I can just remove the static from canDo array but all instances of the same subclass should always have the same values in the canDo array so there is no need to have canDo array in every instances, this will be big waste of memory because i will have too many instances of this class.
class Vehicle {
public static List<string> canDo;
static Vehicle() {
canDo = new List<string>();
canDo.Add("go");
}
}
class Plane : Vehicle {
static Plane() {
canDo.Add("fly");
}
}
class Ship : Vehicle {
static Ship() {
canDo.Add("sail");
}
}
class Main {
static void Main(string[] args) {
Vehicle plane = new Plane();
Vehicle ship = new Ship();
plane.canDo; // Contains (go, fly and sail) i want only (go and fly)
ship.canDo; // Contains (go, fly and sail) i want only (go and sail)
}
}
What is the best way to solve this?
Do not abuse static methods for things that are not static. Simple like that.
Static has no inheritance and is NOT something that CAN have inheritance scenarios in any way.
You are fighting a battle by abusing a feature - not worth fighting. Please learn proper object orientation.
Note that you could also hide the canDo of the base class using new:
class Vehicle
{
public static List<string> canDo = new List<string>() { "go" };
}
class Plane : Vehicle
{
public new static List<string> canDo = new List<string>(Vehicle.canDo);
static Plane()
{
canDo.Add("fly");
}
}
You do not need static variables and constructors for that, just add base constructors(which is done by default, : base() is optional):
class Vehicle {
public List<string> canDo;
Vehicle() {
canDo = new List<string>();
canDo.Add("go");
}
}
class Plane : Vehicle {
Plane() : base() {
canDo.Add("fly");
}
}
class Ship : Vehicle {
Ship() : base() {
canDo.Add("sail");
}
}
UPDATE: based on the comment of #Eben Roux -
public abstract class Vehicle {
protected static List<string> _canDo;
protected abstract List<string> getCanDo();
public List<string> canDo{
{ get {
var _cando = new List();
_cando.AddRange(Vehicle._canDo);
_cando.AddRange(this.getCanDo());
return _cando;
}
}
}
static Vehicle() {
_canDo = new List<string>();
_canDo.Add("go");
}
}
class Ship : Vehicle {
protected static List<string> childCanDo;
protected override getCanDo(){
return Ship.childCanDo;
}
static Ship() {
childCanDo.Add("sail");
}
}
You need an instance of the canDo list per type. So either you can pass in the collection via the constructor or you can have a static on the subtype level.
Edit (to elaborate):
Since your sub class instance all have the same 'abilities' and you don't want to populate a list for each you would need a shared list. You are using inheritance where you probably want composition:
public abstract class Vehicle
{
protected List<string> canDo;
protected Vehicle(List<string> canDo)
{
this.canDo = canDo;
}
}
public class Plane : Vehicle
{
public Plane(List<string> canDo) : base(canDo)
{
}
}
I wouldn't go with a List<string> either but rather encapsulate it in a class that makes business sense (although I understand that this is only an example). To populate the canDo list you could go with a factory or a factory method on a subtype.
There are just so many ways to do this you will need to find something that's comfortable.
Although I did present a static as an alternative (since you were asking about it) I definitely would not use a static for this myself.

What is the best way to inherit an array that needs to store subclass specific data?

I'm trying to set up an inheritance hierarchy similar to the following:
abstract class Vehicle
{
public string Name;
public List<Axle> Axles;
}
class Motorcycle : Vehicle
{
}
class Car : Vehicle
{
}
abstract class Axle
{
public int Length;
public void Turn(int numTurns) { ... }
}
class MotorcycleAxle : Axle
{
public bool WheelAttached;
}
class CarAxle : Axle
{
public bool LeftWheelAttached;
public bool RightWheelAttached;
}
I would like to only store MotorcycleAxle objects in a Motorcycle object's Axles array, and CarAxle objects in a Car object's Axles array. The problem is there is no way to override the array in the subclass to force one or the other. Ideally something like the following would be valid for the Motorcycle class:
class Motorcycle : Vehicle
{
public override List<MotorcycleAxle> Axles;
}
but the types have to match when overriding. How can I support this architecture? Will I just have to do a lot of run-time type checking and casting wherever the Axles member is accessed? I don't like adding run-time type checks because you start to lose the benefits of strong typing and polymorphism. There have to be at least some run-time checks in this scenario since the WheelAttached and Left/RightWheelAttached properties depend on the type, but I would like to minimize them.
Use more generics
abstract class Vehicle<T> where T : Axle
{
public string Name;
public List<T> Axles;
}
class Motorcycle : Vehicle<MotorcycleAxle>
{
}
class Car : Vehicle<CarAxle>
{
}
abstract class Axle
{
public int Length;
public void Turn(int numTurns) { ... }
}
class MotorcycleAxle : Axle
{
public bool WheelAttached;
}
class CarAxle : Axle
{
public bool LeftWheelAttached;
public bool RightWheelAttached;
}
2 options spring to mind. 1 is using generics:
abstract class Vehicle<TAxle> where TAxle : Axle {
public List<TAxle> Axles;
}
The second uses shadowing - and this assumes you have properties:
abstract class Vehicle {
public IList<Axle> Axles { get; set; }
}
class Motorcyle : Vehicle {
public new IList<MotorcycleAxle> Axles { get; set; }
}
class Car : Vehicle {
public new IList<CarAxle> Axles { get; set; }
}
void Main() {
Vehicle v = new Car();
// v.Axles is IList<Axle>
Car c = (Car) v;
// c.Axles is IList<CarAxle>
// ((Vehicle)c).Axles is IList<Axle>
The problem with shadowing is that you have a generic List. Unfortunately, you can't constrain the list to only contain CarAxle. Also, you can't cast a List<Axle> into List<CarAxle> - even though there's an inheritance chain there. You have to cast each object into a new List (though that becomes much easier with LINQ).
I'd go for generics myself.
I asked a similar question and got a better answer, the problem is related to C#'s support for covariance and contravariance. See that discussion for a little more information.

Categories

Resources