In short, I'm hoping to achieve a kind of barebones structure in one place and implement/define in another. I want to better "see" the interconnectedness without all the functionality clouding it up mostly for design discussions, explanations, etc. I could do this with inheritance, but I really don't want to change all the names of everything just to achieve this. Is this a thing somehow?
// Simple File for seeing relationships between classes
public class AllMyObjectTypes // A class because it will be its own object with functionality below all this structural stuff
{
public class Thing1
{
public Thing2[] things2;
public Thing3[] things3;
}
public class Thing2[]
{
public int version;
public Thing1[] thing1Utilizers;
}
public class Thing3[]
{
public string Title;
}
}
// Complicated file for doing all the hard work for Thing1 with all the internal variables to make it happen.
public class Thing1 : Thing1 // Implement itself somehow?
{
// Stuff I want to use and define but not cloud the structure above
private int[] internalStuff;
private string moreInternalStuff;
public void UsefulFunctionButWantSeparated()
{
// Hundreds of lines of code clouding junk up
}
}
Interface & Class declarations
public interface IThing
{
IThing2[] Thing2s();
string DoSomething();
}
public class Thing : IThing
{
private readonly IThing2[] _thing2s = new IThing2[1] { new Thing2() };
public IThing2[] Thing2s() => _thing2s;
public string DoSomething()
{
return "MyText";
}
}
public interface IThing2
{
}
public class Thing2 : IThing2
{
}
Use
IThing thing;
thing = new Thing();
var thing2s = thing.Thing2s();
var txt = thing.DoSomething();
Partial Classes is exactly what I was looking for, but it did require that I don't nest within another class. Unless maybe I made that partial too...? But either way, this gets me closest to my goal
// Simple File for seeing relationships between classes
//public class AllMyObjectTypes // A class because it will be its own object with functionality below all this structural stuff
//{
public partial class Thing1
{
public Thing2[] things2;
public Thing3[] things3;
}
public partial class Thing2[]
{
public int version;
public Thing1[] thing1Utilizers;
}
public partial class Thing3[]
{
public string Title;
}
//}
// Complicated file for doing all the hard work for Thing1 with all the internal variables to make it happen.
public partial class Thing1 // More implementation
{
// Stuff I want to use and define but not cloud the structure above
private int[] internalStuff;
private string moreInternalStuff;
public void UsefulFunctionButWantSeparated()
{
// Hundreds of lines of code [no longer] clouding junk up
}
}
Related
i've got base and derived classes as follows (this is just an example):
class Base_TripLog {
public List<Base_Trip> trips = ...
public Base_TripLog(string log_filename) {
// load stuff into trips
}
}
class Base_Trip {
public string vehicle_id = ...;
public Dictionary<ulong, Base_Waypoint> waypoints = ...
public Base_Trip() {
}
public add_waypoint(ulong epoch_sec, Base_Waypoint waypoint) {
waypoints.Add(epoch_sec, waypoint);
}
}
class Base_Waypoint {
/// time and gps coords
}
class Derived_TripLog : Base_TripLog {
public string company_name;
public new List<Derived_Trip> trips = ...
public Derived_TripLog(string company_name, string filename) : base(filename) {
this.company_name = company_name;
if (trips.Count > 0) {
// do stuff
}
}
}
class Derived_Trip : Base_Trip {
public int duration_sec;
public Derived_Trip() : base() {
duration = compute_trip_duration(waypoints)
}
}
the Derived_TripLog constructor uses the base constructor to load the file of waypoints. trips in the derived class will naturally still be empty. i was planning to copy base.trips into the derived trips.
two question:
is copying the standard way to handle this situation? if the base Trip class had lots of members and collections, it could be it pain to copy all the members.
if copying is the standard approach, then i'm essentially doubling memory usage. (base.trips can be quite large.) it seems i could just do base.trips.Clear() to free up those resources. if there a correct way?
That´s what generics are for. Instead of having a list of trips of different types in every child-class, you have a single list with the generic type within your base-class:
class Base_TripLog<TripType> where TripType: Base_Trip {
public List<TripType> trips = ...
public Base_TripLog(string log_filename) {
// load stuff into trips
}
}
Now you can just inherit this class using the correct generic argument:
class Derived_TripLog : Base_TripLog<Derived_Trip>
{
public string company_name;
public Derived_TripLog(string company_name, string filename) : base(filename)
{
this.company_name = company_name;
if (trips.Count > 0) {
// do stuff
}
}
This way you don´t need to re-declare the property for every class, but just have a single definition for all types that derive from Base_Trip.
I'm trying to get my head around making a simplified way of making items, lists and databases in C# And while everything works, It involved me needing to cast the results out.
So far I have the following
namespace Game.Database
{
public abstract class DatabaseItem : ScriptableObject
{
}
public class DatabaseList : ScriptableObject
{
public List<DatabaseItem> items;
}
public class ShipClass : ScriptableObject
{
public string shipClassID;
new public string name;
}
public class Ship : DatabaseItem
{
public string shipID;
new public string name;
public ScriptableObject shipClass;
}
}
public class Database : MonoBehaviour
{
public List<DatabaseList> lists;
void Start()
{
Ship ship = (Ship)lists[0].items[0];
Debug.Log(shipClass.shipID);
ShipClass shipClass = (ShipClass)ship.shipClass;
Debug.Log(shipClass.shipClassID);
}
}
Bear in mind this is a unity project so these items are being instantiated and data being assigned through the UI.
As you can see I have an abstract for my items and will have multiple types of item, and multiple lists. I am trying to avoid having to make multiple class' for my lists, one for each type of item. So i have abstracted my items off DatabaseItem so that I can store a List of DatabaseItem in my DatabaseList. However this means when reading my data out i need to cast this back into a Ship class.
While this isn't bad for a simple implementation, in production these will be nested requiring multiple casts to get down to the required data.
Unfortunately I find myself lacking in the required c# vocabulary to really google the issue. Looking at the Microsoft User-defined conversion operators and their example just doesn't make sense if it's even what i want to achieve.
EDIT -
The issue if not accessing the data, as I can do that, it's having to break down every level of the data as in the end this will be very generic used for all game data and very nested, so having to cast every level out to be able to break it down is what I'm trying to avoid.
One way would be to expose a method on each type of item that does the writing out of the data, so the calling code doesn't need to know the low level details.
See below, on how to avoid doing any casting.
namespace Game.Database
{
public abstract class DatabaseItem : ScriptableObject
{
public abstract void WriteOut();
}
public class DatabaseList : ScriptableObject
{
public List<DatabaseItem> items;
}
public class Ship : DatabaseItem
{
public string shipID;
new public string name;
public override void WriteOut()
{
Debug.Log(shipID);
}
}
}
public class Database : MonoBehaviour
{
public List<DatabaseList> lists;
void Start()
{
lists[0].items[0].WriteOut();
}
}
This way you are allowing each item type to handle its own writing out. Id suggest thinking carefully about your API.
To be even more SOLID and clean, you could use dependency injection and inject the writing into the type, see below for another example.
This has the benefit of allowing multiple types to use the same writer code and you also keep your class following the single responsibility principle.
namespace Game.Database
{
public interface IWriter
{
void Write(string output);
}
public class ConsoleWriter: IWriter
{
public void Write(string output)
{
Debug.Log(output);
}
}
public abstract class DatabaseItem : ScriptableObject
{
public abstract void WriteOut();
}
public class DatabaseList : ScriptableObject
{
public List<DatabaseItem> items;
}
public class Ship : DatabaseItem
{
private IWriter _writer;
public Ship(IWriter writer)
{
_writer = writer;
}
public string shipID;
new public string name;
public override void WriteOut()
{
_writer.Write(shipID);
}
}
}
public class Database : MonoBehaviour
{
public List<DatabaseList> lists;
void Start()
{
lists[0].items[0].WriteOut();
}
}
Something like this should be a good starting point. The specific implementations need to be adapted to your game's needs. More informations about generic types here.
public abstract class Item: ScriptableObject
{
public string name;
public abstract void Use();
}
public class Ship: Item
{
public string id;
public override void Use()
{
Debug.Log($"I'm a Ship, my name is {name}, my id is {id}.");
}
}
public class Plane: Item
{
public float speed;
public override void Use()
{
Debug.Log($"I'm a Plane, my name is {name}, my speed is {speed}.");
}
}
public class Database: ScriptableObject
{
[SerializeField] private List<Item> items;
public T GetItem<T>(int i) { return (T) items[i]; }
public Item AddItem() { ... }
public Item RemoveItem() { ... }
}
public class DatabaseHolder: MonoBehaviour
{
public Database database;
void Start()
{
Ship ship = database.GetItem<Ship>(0);
// Or...
Plane plane = database.GetItem<Plane>(1);
}
}
My main class Computer interacts with a number of external systems and currently has the logic for getting/updating their info crammed into it.
I want to move the logic for each system to it's own separate class and i've been able to part of the way there but i'm having trouble calling a method on them.
I've only just recently started playing around with generics so this is probably badly written code, apologies for your eyes in advance.
These are my System classes
public class System
{
public string Name { get;set; }
}
public class System<T> : System
{
public virtual T GetData() => default(T);
public virtual void UpdateData() {}
}
public interface ISystem<T>
{
T GetData();
void UpdateData();
}
These are the systems i've created using the System classes:
public class ComplexSystem : ISystem<RegistryKey>
{
public string GetData() => MethodThatGetsRegistryData();
public bool UpdateData() => MethodThatUpdatesRegistry();
}
public class IntSystem : ISystem<int>
{
private int value = 9;
public int GetData() => this.value;
public void UpdateData()
{
this.value = 3;
}
}
public class StringSystem : ISystem<string>
{
private string value = "hello";
public string GetData() => this.value;
public void UpdateData()
{
this.value = "updated";
}
}
and this is how i'm trying to use the whole thing:
public class Computer
{
public List<System> AssociatedSystems = new List<System>();
public Computer()
{
this.AssociatedSystems.Add(new System<ComplexSystem> {Name="ComplexSystem"});
this.AssociatedSystems.Add(new System<IntSystem> {Name="IntSystem"});
this.AssociatedSystems.Add(new System<StringSystem> {Name="StringSystem"});
}
public void UpdateDataWhenComputerIsChanged()
{
// is it possible to loop through them and call UpdateData on each one without know what generic they are?
foreach (var associatedSystem in this.AssociatedSystems)
{
// something like...
associatedSystem.UpdateData();
}
}
}
Which results in
System does not contain a definition for UpdateData() and no extension method could be found
I'm not married to the code above so if there's a better way of doing it i'm all for learning. I'm essentially looking for a way to have a list of classes that contain data logic (like GetData() and UpdateData()) so i don't have to put that logic into my main class (Computer)
So function UpdateData does not exist in System and that is why you cant call it. I would suggest introducing an ISystem interface and put Name (if you need it) and UpdateData in that and let the generic ISystem<T> interface inherit from that.
public interface ISystem
{
string Name {get;set;}
void UpdateData();
}
public interface ISystem<T> : ISystem
{
T GetData();
}
public class Computer
{
public List<ISystem> AssociatedSystems = new List<ISystem>();
.....
foreach (var associatedSystem in this.AssociatedSystems)
{
associatedSystem.UpdateData();
}
}
Yes there are multiple ways to do this. The ones that I can think of are:
Type checking each System in the loop
Adding a Type property to system
Adding a UpdateData(object) or UpdateData(SomeHighLevelType)
If you need more help please specify the nature of your systems. Are they limited to some specific types or you want is extendable for ever and how much speed critical is your project and I can elaborate more
i'm trying to build a sort of framework for some base process in an app. There is some common behavior where i have to execute some operations but these operations are different depending on some scenarios. I have done something i'm not sure if it's considered a bad practice to make something like this:
public interface IMyDto
{
string makerIdentifier { get; set; }
}
public class DtoOne:IMyDto
{
public string makerIdentifier { get; set; }
//Custom properties for ConcreteOne
}
public class DtoTwo:IMyDto
{
public string makerIdentifier { get; set; }
//Custom properties for ConcreteTwo
}
public abstract class AbstractMaker
{
public abstract void DoSomething(IMyDto myInterface);
}
public class ConcreteMakerOne:AbstractMaker
{
public override void DoSomething(IMyDto myInterface)
{
var concrete = myInterface as DtoOne;
// If concrete is not null..do stuff with DtoOne properties
}
}
public class ConcreteMakerTwo : AbstractMaker
{
public override void DoSomething(IMyDto myInterface)
{
var concrete = myInterface as DtoTwo;
// If concrete is not null..do stuff with DtoTwo properties
}
}
public class Customer
{
public void MakeSomething(IMyDto myDto)
{
var maker = GetMaker();
maker.DoSomething(myDto);
}
private AbstractMaker GetMaker()
{
//Stuff to determine if return ConcreteOne or ConcreteTwo
}
}
The code im not happy with is the:
var concrete = myInterface as DtoOne;
I would appreciate a lot if someone could give me some advide or tips about a pattern or good oop practice for this scenario.
It's not clear what all of your use cases are, but one option might be generics:
public abstract class AbstractMaker<T> where T:IMyDto
{
public abstract void DoSomething(T myInterface);
}
public class ConcreteMakerTwo : AbstractMaker<DtoTwo>
{
public override void DoSomething(DtoTwo myInterface)
{
// now you are certain that myInterface is a DtoTwo
}
}
I am not sure if I understand correctly what are you asking about, but why not just put method DoSomething in IMyDto and implement it differently in DtoOne, DtoTwo, etc.? There would be only one Maker and would always call the same method.
I would like to declare a generic field inside PakFileFormat class in order to be replaceable with concrete types in derived classes.
This will be fine:
public class Pak10File : PakFileFormat
{
public Pak10File()
{
this.toc = new PakFileToc<Pak10FileEntry>();
}
}
How to fix this ?
Thanks.
Related classes
public abstract class PakFileEntry { }
public class Pak10FileEntry : PakFileEntry
{
public long size; // 8 bytes
public long csize; // 8 bytes
public long offset; // 8 bytes
public byte fname_len; // 1 byte
public char[] fname; // variable
}
public class PakFileToc<T> where T : PakFileEntry { }
public abstract class PakFileFormat
{
protected PakFileToc<T>; // ----- This does not compile.
}
You would need to make PakFileFormat generic also in order to make that compile.
In order for this to be useful though, you will probably need to make PakFileFormat implement some kind of non-generic interface.
It is hard to give more detail than this without knowing exactly what you need PakFileFormat to actually do, or how it will be used.
public abstract class PakFileFormat<TPakFile> where TPakFile : PakFileEntry
{
protected PakFileToc<TPakFile> toc;
}
The sub-classes would then look something like:
public class Pak10File : PakFileFormat<Pak10FileEntry>
{
public Pak10File()
{
this.toc = new PakFileToc<Pak10FileEntry>();
}
}