I've been learning C# the past couple of months and we've been tasked with a small project where there's this specific requirement:
We need to design the UI part of the project in such way, that we can figure out some random class fields and then get the input from a user to initialize those fields.
For example, in one run of the program we have this class A that has two integer fields.
In the UI section, we need to figure out class A has two integers, then we need to receive 2 integers from the user and pass them back for initialization.
Another scenario:
We have class B that has a boolean and an Enum field, and we need to do the same.
I've been leaning towards using reflection to gather the data needed in runtime, but I'm having a lot of problem figuring out how to actually receive the required input from user.
Another hurdle is that we were told that reflection isn't gonna help us and/or not required to fulfill this task.
I'm fairly inexperienced with the language so I assume there may be some other ways to implement this that I'm not aware of, but conceptually speaking - I really can't grasp how it is possible.
Here's some basic classes hierarchy to give a better example:
public abstract class Shape
{
private Point location;
private string color;
}
public abstract class NonCircular : Shape
{
private int edgesNumber;
}
public class Circle : Shape
{
private float radius;
private float diameter;
}
public class Triangle : NonCircular
{
public enum AngleType { Right, Acute, Obtuse }
public enum EdgePropery { Equilateral, Isosceles, Scalene }
private AngleType angleType;
private EdgePropery edgePropery;
private float angle1, angle2, angle3;
}
Going with this example - let's say that class 'Triangle' is being added to the solution later-on, after the project is done.
We first construct the abstract class 'Shape' with some of the basic fields that are shared among everyone, and then according to the requirements, the UI needs to receive the fields:
angleType, edgePropery, and angles1-3
and pass back values to the logical part of the project in order to initialize them properly.
You could add a method to the base class that returns information on the fields that need to be initialized. Each shape then overrides this method and returns its respective fields.
A second method is needed to actually initialize the fields after the UI got to know the required fields and had the user enter the values.
The main problem then is that a subclass does not know about any private fields in its base class and can not initialize them. This can be solved by always calling the base implementation of GetFieldInfo() and InitFields() in every override.
To ensure the collection of provided values is "consumed" correctly you could use a stack. Every base class will Pop() as many values from the collection it needs to initialize itself and then leaves the rest to its derived classes.
The same principle is used when accumulating all the fields from base classes and derived classes with GetFieldInfo().
Of course all this only works if the UI creates the Stack of values correctly, i.e. it must respect the order and Types it got via GetFieldInfo().
public abstract class Shape {
private Point location;
private string color;
public virtual IEnumerable<Type> GetFieldInfo() {
yield return location.GetType();
yield return color.GetType();
}
public virtual void InitFields(Stack<object> values) {
location = (Point)values.Pop();
color = (string)values.Pop();
}
}
public abstract class NonCircular : Shape {
private int edgesNumber;
public override IEnumerable<Type> GetFieldInfo() => base
.GetFieldInfo()
.Append(edgesNumber.GetType());
public override void InitFields(Stack<object> values) {
base.InitFields(values);
edgesNumber = (int)values.Pop();
}
}
public class Circle : Shape {
private float radius;
private float diameter;
public override IEnumerable<Type> GetFieldInfo() => base
.GetFieldInfo()
.Append(radius.GetType())
.Append(diameter.GetType());
public override void InitFields(Stack<object> values) {
base.InitFields(values);
radius = (float)values.Pop();
diameter = (float)values.Pop();
}
}
public class Triangle : NonCircular {
public enum AngleType { Right, Acute, Obtuse }
public enum EdgePropery { Equilateral, Isosceles, Scalene }
private AngleType angleType;
private EdgePropery edgePropery;
private float angle1, angle2, angle3;
public override IEnumerable<Type> GetFieldInfo() => base
.GetFieldInfo()
.Append(angleType.GetType())
.Append(edgePropery.GetType())
.Append(angle1.GetType())
.Append(angle2.GetType())
.Append(angle3.GetType());
public override void InitFields(Stack<object> values) {
base.InitFields(values);
angleType = (AngleType)values.Pop();
edgePropery = (EdgePropery)values.Pop();
angle1 = (float)values.Pop();
angle2 = (float)values.Pop();
angle3 = (float)values.Pop();
}
}
It just occured to me that using GetType() might count as reflection. But GetFieldInfo() could also return an IEnumerable<object> created from the field values directly. The UI could then use the is operator to check the field type and show the appropriate UI element (text box, number box, drop down etc).
By the way, I think this is a rather ugly solution. The back-and-forth between the base and sub classes makes for highly unreadable code. In a real-world application I'd probably rather take the performance hit of using reflection in favor of having the type inspection and initialization logic in one place. In the above solution this logic is spread all over your model classes.
Related
I'm trying to practice with inheritance and just in general having scripts interact with each other and I thought doing a simple effect system could be fun, but I'm a bit stuck on how to structure things.
I keep wanting to do this
public abstract class BaseEffect : ScriptableObject
{
//not sure if this is a good use of enum
public enum EffectType
{
harm, //can be applied to enemies
help, //can be applied to allies
self //can be applied to yourself
}
public string name;
public string description;
public float duration;
public bool canStack; //can the effect be applied multiple times
public EffectType type;
//I'd probably also write my apply and remove effect methods here
}
And then a bunch of derived classes like this
public class TestEffect : BaseEffect
{
//maybe include some variables specific to this effect
//when the effect gets applied have this run every frame to od whatever the effect does
public void DoEffect()
{
}
}
I have a feeling though that this isn't a good way to go about doing this or at least the way I've written it isn't good so looking for some advice to get on the right track
This arrangement may benefit from an abstract method or usage of an Interface consumed by an abstract class to enforce derived classes to respond to events. Speaking of events, you could also wire the derived calls up through events. In simple terms, introduce an abstract method in the base class, which must be implemented in derived classes. Then call the method in the base classes "plumbing" when everything special about the event is ready.
public abstract class BaseEffect : ScriptableObject
{
protected abstract void DoEffect();
private SomeMethod()
{
if(canDoEffect)
DoEffect();
}
}
Basically I'm trying to create a attatchment system for a 2D platform/shooter game, the weapon system is working great but I want to implement some attachments, diferent barrels, magazines even ammo types.
For the simpler ones that just modify a stat I was thinking of just creating a class or even a struct with all the possible stats (damage, recoil, spread etc) and just setting them to the appropiate values (+1, -5, 0 if it doesn't use it). However, there are some ideas that might require a separate method/function, like shooting different bullets.
My main question is would it be more effective/efficient to just make smaller scripts for the edge cases and a main one for the simple stat changers. Or should I just overload a main script/class with methods for all the possible attachments?
There aren't that many "special" attachments, but i'd like to make a system that expandable if possible.
Im not an expert programmer (I just learned about enums a couple days ago!) so any suggestions are greatly appreciated.
I would use Unity's ScriptableObject class to create an abstract class then inherit from that abstract class to create more spesific classes and abstract classes.
Then I would create my attachments etc. in unity editor and modify whatever value I want from it.
An example armor piece would inherit the following ArmorItem class and use the ApplyEffect method to make the player bigger to show that you can make any type of modification.
ItemBase class
using UnityEngine;
public abstract class ItemBase: ScriptableObject
{
public string ItemName;
public abstract void ApplyEffect();//override this method for any edge case items
}
ArmorItem
public abstract class ArmorItem: ItemBase
{
public float Armor;//use this however you want
}
EdgeCaseArmor
[CreateAssetMenu(menuName = "Items/Armor/EdgeCaseArmor")]
public class EdgeCaseArmor: ArmorItem
{
public override void ApplyEffect()
{
//find player and make it bigger
GameObject.FindGameObjectWithTag("Player").transform.localScale *= 1.5f;
}
}
Obviously you will need to load items and somehow call ApplyEffect. You can do it at the start of the game by adding this to a start method.
var item = Resources.Load("path to your scriptable object that inherits ItemBase") as ItemBase;
item.Activate();
How you load the items and call them is up to you. You will need to save your scriptable objects in Assets>Resources folder(create one if you haven't created one already).
You can also make multiple armors with different names, armor values etc. like this.
Note that if you want to have an armor with no special effect you will need to make ArmorItem a normal class or make a NormalArmor class that inherits ArmorItem. Just leave the ApplyEffect function empty if you don't want any special effects.
This is a fairly general question so keep in mind that you may get several varying opinion-related answers.
With that said, the biggest suggestion that I would give is to look into Inheritance. Using a series of interfaces and classes to more refine the base concept of "item modifications".
For instance, I would create an interface:
interface IItemModification
{
void Apply();
}
Any more refined modification class or interface would implement (in the case of a class) or inherit (in the case of another interface) this interface.
In this example we will just create a base class that implements that interface:
public class ItemModification : IItemModification
{
public void Apply()
{
// Logic to apply modifications to the item.
}
}
In the case above, you now have a very basic class that represents an item modification which contains the implementation of the interface.
Next you might want to go into further detail, perhaps by creating item type implementations:
public class WeaponItemModification : ItemModification
{
public ArmorItemModification(StatModifiers modifiers, AttackType attackType)
{
this.Modifiers = modifiers;
this.Attack= attackType;
}
public AttackType Attack
{
get; set;
}
public StatModification Modifiers { get; set; }
}
public class ArmorItemModification : ItemModification
{
public ArmorItemModification(StatModifiers modifiers, DefenseType defenseType)
{
this.Modifiers = modifiers;
this.Defense = defenseType;
}
public DefenseType Defense
{
get; set;
}
public StatModification Modifiers { get; set; }
}
Of course a logical progression of that would be more specific item types:
public class VestModification : ArmorItemModification
{
public VestModification(StatModification modifiers, DefenseType defenseType, AreaProtectionType areaProtectionType)
{
this.Modifiers = modifiers;
this.Defense = defenseType;
this.AreaProtection = areaProtectionType;
}
public AreaProtectionType AreaProtection
{
get; set;
}
}
These are just some basic examples to point you in the right direction. I would suggest reading up on inheritance concepts to get a better understanding of it.
I need a system of classes that describes a planetary system.
My first class is an atomary space body:
public class SpaceBody
{
public string Name;
public float Mass;
// and so on
}
The second one is a system of space bodies and it also is SpaceBody:
public class SpaceBodySystem<ChildType>: SpaceBody where ChildType: SpaceBody, new()
{
// ...
public List<ChildType> Children;
// ...
}
Next, I have a star:
public class Star: SpaceBodySystem<SpaceBody>
{
public float Intencity;
// ...
}
And finally, the whole star system is something like this
(it can have more than one star):
public class StarSystem: SpaceBodySystem<Star>
{
public bool OccupiedByAliens;
// ...
}
The problem is:
The stars should have planets (SpaceBodySystem) which in turn, may have their satellites and those satellites also may have their own satellites and so on... nesting depth is unlimited.
It's impossible with my current class system.
I have to write something like this but this ugly solution has limited hierarchy level.
public class StarSystem: SpaceBodySystem<SpaceBodySystem<SpaceBodySystem<SpaceBody>>>
{
public float Intencity;
// ...
}
I ask the community to give me some advises how this structure can be improved.
I thought about other scheme (interfaces, composition + delegation) and didn't managed to get an acceptable solution.
Many thanks for any help.
If you need the possibility to have multiple suns in a system, maybe you also want the possibility of two planets sharing a moon.
In that case, maybe you should have a SubSystem, which has an array of main bodies and an array of satellites. In a solar system, you can use stars as the main bodies and the planets as satellites. In a galaxy, maybe you can define some abstract centerpoint/waypoint as the main body and all the solar systems are satellites.
So for our solar system, you've got the SubSystem 'SolarSystem', with main body Sun and sattelites planets, each of which are subsystems as well. Subsystem Earth has a main body Earth and a satelite Moon.
Having a SubSystem Earth with one MainBody Earth might sound a bit redundant, but maybe you can solve that by using interfaces, so a simple subsystem like that (with one main body) can be implemented by a single class that implements both ISubSystem and IMainBody.
Or you can keep the implementation easier and make Earth(system) a separate subsystem with an array with one main body, which is Earth(planet) and an array with one satelite, which is the SubSystem Moon(system), containing main body Moon and no satellites.
I think one class will do to set up a planetary system:
public class SpaceBody
{
public string Name;
public float Mass;
public float Distance;
public bool clockwise;
//...
public SpaceBody RevolvesAround;
List<SpaceBody> Satellites;
}
If your base class for systems can have children which are themselves instances of, or derived from, that same base class, then you don't need to nest like that. Let me give an example:
public class SpaceBodySystem<ChildType>: SpaceBody where ChildType: SpaceBody, new()
{
public List<ChildType> Children;
}
So, a SpaceBodySystem has children that are SpaceBody types, and it is itself a SpaceBody.
public class StarSystem : SpaceBodySystem<Star>
{
}
This class can represent a star, or a binary pair of two stars, or whatever.
public class PlanetarySystem : SpaceBodySystem<Moon>
{
public Planet CentralPlanet;
}
This can represent a planet with any number of moons, where Planet inherits from SpaceBody.
public class SolarSystem : SpaceBodySystem<PlanetarySystem>
{
public StarSystem CoreStar;
}
This class can now represent a solar system with some configuration of stars, and children which are all planets which may have moons.
In short, you don't need to keep nesting SpaceBodySystem<SpaceBodySystem<SpaceBodySystem<SpaceBody>>> because SpaceBodySystem inherits from SpaceBody, so if you just have SpaceBodySystem<SpaceBody>, then that inner SpaceBody might be a SpaceBodySystem, which might have further children, but you don't need to know that. That's the beauty of polymorphism.
Need to say in addition, I want to load my system from data file.
Suppose, I have this input data (in attachment).
And I have virtual method that reads and creates an object of SapceBody.
class SpaceBody...
{
...
public virtual void CreateGameObject()
{
instance = new GameObject();
}
...
}
class SpaceBodySystem...
{
...
public override void CreateGameObject()
{
base.GameObject();
foreach(ChildType child in Children)
{
child.CreateGameObject();
}
}
...
}
class Star: SpaceBodySytem<SpaceBody>
{
...
public override void CreateGameObject()
{
base.GameObject();
doExtraWorkForTheStar();
}
...
}
StarSystem.CreateObject();
// for attached file, will load and create one star (Sun) and nine planets.
So, if I use the declaration proposed by anaximander, the system doesn't see children of children.
For example, the Earth is SpaceBody (but should be SpaceBodySytem) and will not create Moon in this case.
The GolezTrol's idea is fine.
solarsystem.json
i am sorry if this has been asked before, but i don't really know if i'm phrasing the question right:
So, let's say i have this classes:
class Shape{
int Area
}
class Triangle:Shape{
string type_of_triangle;
}
class Star:Shape{
int Number_of_Points;
}
and a function that returns a shape typed List wich contains both triangle and shape objects in it. when i try to access triangle's or star's properties, visual studio only let's me access the parent's properties.
So, basically my question is: How can i access the child's properties if the objects are stored in a parent-type variable??
Shape unknownShape = new Triangle();
if(unknownShape is Triangle){
((Triangle)unknownShape).type_of_triangle;
}
I would suggest giving a little more thought to the design of you class hierarchy. Off the top of my head I would propose you can place all of the properties you have defined for your derived shapes within the parent. Further, you might want to consider making some of them methods which return values.
While it is not part of your current example, any shape, including a circle has a finite number of points (a circle simply has zero). A generic "shape_family" property might represent the string classification for the specific derivation of the shape class ("Triangle", "Star", etc).
The shape_subtype might represent specific variations ("Right Triangle", "Isoceles Triangle", etc.). Then, if you define the points as, well, POINTS and add them to a list, you will not only have specified locations for them (if that is not beyond the scope of your program), but you will have a count as well. From there you can probably work out some additional logic to map the sides/verticals, and compute such things as Area, perimeter, etc.
Consider (but please note that I am only now branching into C# and Java from vb.net, so if I butcher the code here, try to focus on the class structure, NOT my syntax . . .):
Edit: 4/22/2011 7:41 AM - Ooops. Forgot to make the Class abstract. If methods on a class are defined as "abstract", then the class itself must be abstract as well, meaning the abstract base cannot be directly instantiated. Here is a link to more info on abstract classes and methods/
public abstract class Shape
{
int Area;
string shape_family;
string shape_subtype;
list<point> Points
public int number_of_points()
{
return points.count
}
public abstract int perimeter_lenngth()
public abstract int area()
}
class Triangle : Shape {
//Example of Triangle-specific implementation:
public override int perimiter_length {
//You code to obtain and compute the lengths of the sides
}
//Example of Triangle-specific implementation:
public override int area {
//Your code to obtain and compute
}
}
class Star : Shape{
//Example of Star-specific implementation:
public override int perimiter_length {
//Your code to obtain and compute the lengths of the sides
}
//Example of Star-specific implementation:
public override int area {
//Your code to obtain and compute
}
}
class Circle : Shape {
point center;
int radius
// Example of Circle-specific implementation:
public override int perimiter_length {
return 2*3.14*radius
}
// Example of Circle-specific implementation:
public override int area {
return 3.14*radius^2
}
}
I am writing a simple graphic editor for a university project using C#.
I created a hierarchy where every type of shape - circles, rectangles, ellipses, ... - are inherited from a base class Shape, it contains a shape color as a protected field.
public abstract class Shape {
protected Color color;
public Shape(Color c) {
color = c;
}
public Color FigureColor {
get { return color; }
protected set { color = value; }
}
public abstract void render(Bitmap canvasToDrawOn);
public abstract void unrender(Bitmap canvasToDrawOn);
public abstract void renderPrototype(Bitmap canvasToDrawOn);
}
The idea is that I want every type of shape to encapsulate it`s geometry part, for example:
public class TwoDPoint: TwoDShape {
Point2DGeometry point;
public TwoDPoint(Color c, Point2DGeometry p): base(c) {
point = new Point2DGeometry(p);
}
public struct Point2DGeometry {
Int32 x;
Int32 y;
public Point2DGeometry(Int32 X, Int32 Y) {
x = X;
y = Y;
}
public Point2DGeometry(Point2DGeometry rhs) {
x = rhs.Abscissa;
y = rhs.Ordinate;
}
public Int32 Abscissa {
get { return x; }
private set { x = value; }
}
public Int32 Ordinate {
get { return y; }
private set { y = value; }
}
}
Ellipse class will encapsulate EllipseGeometry, etc.
Is it a good decision in terms of OO design, and if it is, may be it is the better idea to create a parallel hierarchy of this geometry-only types?
I think the answer is yes, because it follows along in the track laid down by the venerated MVC pattern.
Another advantage is that it gives you the option of swapping out graphics libraries without having to rewrite all those base geometric classes. Use an interface to make that even easier to do.
I would say that it depends. Are you going to reuse your geometries objects outside of your shape objects, or share geometry objects as Flyweights? If not, you may be complicating your class hierarchy unnecessarily.
Looking over your code you may also want to consider the following:
Having some sort of naming convention between your private fields and your public properties. There's no point getting fancy with Abscissa/Ordinate when your private variables are x/y and your constructor takes X/Y. Ditto Color and FigureColor in Shape.
In Shape, why make "color" protected, when "FigureColor" also has a protected setter? In most APIs (and you can think of your abstract class as an API to it's derived classes) you'll want to minimize the confusion of which members to use when changing state. In this particular example, I'd most likely make "color" private.
Watch for "internal classes" in your class hierarchy which don't add any value. For instance, you have an abstract Shape class, and from the look of it, TwoDShape as well. What's the difference between the two? Do you have support for 3 dimensions? Does your inheritance tree look more like a stick?
HTH, and good luck with your project.