I am trying to create a program that allows the user to check into a hotel room. The program should check if the room is free and then allocate one of the free rooms if any are available. I have multiple rooms types such as a single room, a double room, a twin room and so on which all need to inherit from the base class Room.
Here is my code currently.
public class Room
{
public static bool[] av = { false, true, false };
public bool availability()
{
bool a = false;
foreach (var roomAv in av)
{
a = a || roomAv;
}
return a;
}
public bool availability(int room)
{
return av[room];
}
public int allocate()
{
if (availability())
{
int room = 0;
while (!av[room])
{
room++;
}
av[room] = false;
return room;
}
else
{
return -1;
}
}
public static void roomStatus()
{
for (int i = 0; i < av.Length - 1; i++)
{
Console.WriteLine(i + av[i].ToString());
}
}
}
class SingleRoom
{
}
The functions I have defined in the room class need to be usable by all the different room types but each hold their own separate array stating whether they are available or not. How can I do this? How can I access those functions for each class but on there own separate array instead of performing them just on the 'av' array like I have currently.
As you said you are new to C#, I would suggest to rethink on structure. You are in object-oriented paradigm. What you are thinking is plain old C-function oriented programming.
public class Room
{
public bool IsAvailable {get; set;}
public RoomType RoomType {get; set;}
public int RoomNo {get; set;}
public int Floor {get; set;}
public string RoomName {get; set;}
}
public enum RoomType
{
Single,
Double,
Twin,
King,
HoneymoonSuite
}
public class RoomManager
{
public List<Room> AllRooms {get; set;}
public RoomManager()
{
AllRooms = new List<Room>();
AllRooms.Add(new Room(){ RoomType=RoomType.Single,
RoomNo=1,
Floor=1,
RoomName="A101",
IsAvailable=true});
AllRooms.Add(new Room(){ RoomType=RoomType.Double,
RoomNo=2,
Floor=1,
RoomName="A102",
IsAvailable=false});
AllRooms.Add(new Room(){ RoomType=RoomType.HoneyMoonSuite,
RoomNo=1,
Floor=2,
RoomName="A201",
IsAvailable=true});
}
public bool IsAvailable(int roomNo)
{
//You need to check if roomNo is a valid RoomNo
return AllRooms.Any(r=>r.RoomNo==roomNo && r.IsAvailable);
}
public bool IsAvailable(string roomName)
{
//You need to check if roomName is valid RoomName
return AllRooms.Any(r=>r.RoomName==roomName && r.IsAvailable);
}
}
The functions i have defined in the room class need to be usable by
all the different room types but each hold their own separate array
stating whether they are available or not. how can i do this?
When you use the static keyword for a variable, you're saying the variable belongs to the type itself instead of the object instance. Quoting from MSDN Docs:
Use the static modifier to declare a static member, which belongs to
the type itself rather than to a specific object.
In other words, your array is "owned" by the class Room, not by individual objects of type Room created with new. If you want each object instance to own its own private member variables, then the static keyword needs to be removed. I.e.
public static bool[] av = { false, true, false };
should be:
public bool[] av = { false, true, false };
Note that the same applies to method names, i.e., if you use the static keyword on a method, the method is "owned" by the class/type itself, and not the individual object instances. This means, your roomStatus method must be used as Room.roomStatus() and trying new Room().roomStatus() would not be possible.
I'd actually recommend that you remove the array and turn this into a property, so that you can simply do something like:
Room r = new SingleRoom();
if(r.IsAvailable)
{
// ...
}
You should also refactor your code to follow .NET naming conventions for your methods, variable names, and make better use of object-orientation. I think Niraj Doshi's post is a good step in that direction.
Since you're new to C#, I'd recommend you get a hold of the book Effective C# by B. Wagner.
Update - Refactored Code
This is my take on refactoring the code, having a RoomManager, a IRoom interface, an abstract implementation of the IRoom interface called Room with code and functionality common to all rooms, a concrete SingleRoom for a more specific type, and a TextView class to manage how the data will be presented/displayed to the user (i.e. text-based output).
Notice that this following the Model-View-Controller (MVC) design pattern, with the Room classes being the models (i.e. data), the TextView being responsible for displaying the data (i.e. presentation), and the Main program itself being the controller (i.e. coordinating the other two).
Main Program
The program simply adds some rooms and then displays information for each of them, based on the manager's capacity.
using System;
using System.Collections.Generic;
namespace HotelRoomManager
{
class MainClass
{
public static void Main (string[] args)
{
RoomManager mgr = new RoomManager (5);
for (uint i = 0; i < mgr.Capacity; ++i)
mgr.AddRoom (new SingleRoom (1, i + 1) );
List<IRoom> rooms = mgr.GetAllRooms ();
TextView view = new TextView ();
view.RenderHeader ();
view.RenderModels (rooms);
mgr.RemoveAllRooms ();
}
}
}
IRoom Interface
The interface defines a type and is the basis for all the rooms. Interfaces are used to define contracts with clients, and does not rely on implementation details, which makes it a good object-oriented practice.
using System;
namespace HotelRoomManager
{
public enum BedType
{
Single,
Double,
Twin,
Queen,
King
}
public interface IRoom
{
BedType BedType { get; }
uint Floor { get; }
uint Number { get; }
bool IsOccupied { get; set; }
}
}
Abstract Room
The room simply contains code that is common to all rooms, regardless of their own individual details.
using System;
namespace HotelRoomManager
{
public abstract class Room : IRoom
{
private uint floor;
private uint number;
private bool occupied;
public Room (uint floor, uint number)
{
this.floor = floor;
this.number = number;
occupied = false;
}
public uint Floor {
get { return floor; }
}
public uint Number {
get { return number; }
}
public abstract BedType BedType { get; }
public bool IsOccupied {
get { return occupied; }
set { occupied = value; }
}
override public string ToString() {
return "Room(floor=" + floor + ", number=" + number + ")";
}
}
}
Concrete SingleRoom
By this point, this room only needs to report its actual type. It doesn't need to do anything special in addition to the common functionality already available.
using System;
namespace HotelRoomManager
{
public sealed class SingleRoom : Room
{
public SingleRoom (uint floor, uint number) : base(floor, number)
{}
override public BedType BedType {
get { return BedType.Single; }
}
}
}
The RoomManager
The manager simply helps to keep track of all the rooms and provides a simplified interface to interact with the collection.
using System;
using System.Collections.Generic;
namespace HotelRoomManager
{
public class RoomManager
{
private List<IRoom> rooms;
public RoomManager (uint capacity) {
rooms = new List<IRoom> ();
rooms.Capacity = (int) capacity;
}
public void AddRoom(IRoom room) {
rooms.Add (room);
}
public void RemoveRoom(IRoom room) {
rooms.Remove (room);
}
public List<IRoom> GetAllRooms() {
return rooms;
}
public void RemoveAllRooms() {
rooms.Clear ();
}
public uint Capacity {
get { return (uint) rooms.Capacity; }
}
}
}
The TextView
The sole responsibility of the view is to decide how the data from the models will be presented to the user. This decouples the data itself from how the data is displayed, making your system easier to maintain and expand. You can also have multiple views available instead of having to choose between one or the other.
using System;
using System.Collections.Generic;
using System.Text;
namespace HotelRoomManager
{
public class TextView
{
public TextView () {}
public void RenderHeader() {
Console.WriteLine ("Hotel Management System");
Console.WriteLine ("-----------------------");
}
public void RenderModels(List<IRoom> rooms) {
StringBuilder sb = new StringBuilder ();
foreach (IRoom r in rooms) {
sb.Append ("Floor : " + r.Floor + "\n");
sb.Append ("Number : " + r.Number + "\n");
sb.Append ("Bed : " + r.BedType + "\n");
sb.Append ("Occupied: " + (r.IsOccupied ? "Yes" : "No") + "\n\n");
}
Console.WriteLine (sb.ToString ());
}
}
}
Output
A quick run of the program will produce the following output:
Hotel Management System
-----------------------
Floor : 1
Number : 1
Bed : Single
Occupied: No
Floor : 1
Number : 2
Bed : Single
Occupied: No
Floor : 1
Number : 3
Bed : Single
Occupied: No
Floor : 1
Number : 4
Bed : Single
Occupied: No
Floor : 1
Number : 5
Bed : Single
Occupied: No
This is pretty simple, instead of a field, use a property:
public class Room
{
public virtual bool[] av { get; set; } = { false, true, false };
//All of your functions remain unchanged except you need to remove static
}
Then in your derived classes:
public class SingleRoom : Room
{
public override bool[] av { get; set; } = { true, true, false };
}
The inherited rooms will set the array which will be used in the base functions for availability so you only have to write it once.
This is another plus of properties over fields, where you can set a property such that it can be inherited. The only thing that was really "wrong" with your original code was that the array and some methods were declared static meaning that it was the same across all instances of the class. Availability should be an instance-level field/property, not a type-level one.
Your original code could work if you remove the static and made your derived classes like this:
public class SingleRoom
{
public SingleRoom
: base()
{
//Redefine the values of the array.
av = { true, true, false };
}
}
You put the array as static, meaning that all access to the array reaches the same object.
Remove that and each will have their own.
As per comments - the static identifier should be removed from the roomStatus method as well.
Related
There's a factory PizzaMaker.GetPizzaObject(PizzaNames pizzaName) which accepts an enum name of one of the pizzas and returns a Pizza object, which stores the amount of each ingredient required in grams:
public class Pizza
{
//the list of all possible properties of a class. Some class exemplars should have some of properties to be disabled.
public int cheese { get; set; }
public int ham { get; set; }
public int pepperoni { get; set; }
}
Since not every type of pizza contains every type of ingredient I want my factory to enable only certain properties in the Pizza object, while the rest should be unavailablefor outside code (for any code for that matter).
My attempt at solution. General C&C welcome:
namespace Testing
{
class Program
{
static void Main(string[] args)
{
PizzaMaker pizzamaker = new PizzaMaker();
Pizza newPizza = pizzamaker.GetPizzaObject(PizzaMaker.PizzaNames.HamAndCheese);
newPizza.cheese = 100;
newPizza.ham = 80;
newPizza.pepperoni = 100; // should throw an error, HamAndCheese shouldn't have "Pepperoni" available.
}
}
public class PizzaMaker
{
//Enum containing all pizza types, used as an argument in PizzaMaker.GetPizzaObject factory
public enum PizzaNames
{
pepperoniPizza,
FourCheese,
HamAndCheese
}
// class factory
public Pizza GetPizzaObject(PizzaNames pizzaName)
{
Pizza result = pizzaName switch
{
PizzaNames.pepperoniPizza => CreatePizza(false, true), //pepperoni has no ham property, has cheese property
PizzaNames.FourCheese => CreatePizza(false, false), //pizza four cheeses has neither ham, nor pepperoni
PizzaNames.HamAndCheese => CreatePizza(true, false), //ham and cheese pizza has ham, but not pepperoni
};
return result;
}
private Pizza CreatePizza(bool hasHam, bool haspepperoni)
{
Pizza result = new Pizza();
hasHam = true ? result.ham.DoSomething(); // somehow enable or disable the property based on wheither it has Ham, pepperoni etc.
haspepperoni = true ? result.pepperoni.DoSomething; // same
// some initialization code, optional
return result;
}
}
public class Pizza
{
//the list of all possible properties of a class. Some class exemplars should have some of properties to be disabled.
public int cheese { get; set; }
public int ham { get; set; }
public int pepperoni { get; set; }
}
}
P.S. the .DoSomething() method is a placeholder for solution, because I suppose something should be done in that place in the code, but I don't know exactly what to do.
I think you are tackling this problem in the wrong way, it's better and more maintainable and less error-prone to have a BasePizza class that contains common properties, then you create a derived class for each of your enum types where you put only properties specific to that Pizza Type.
public class BasePizza
{
// Common properties, like pizza type/name and size
public PizzaNames Name{ get; set; }
// public PizaSize Size { get; set; }
}
public class HamAndCheesePiza: BasePiza
{
public int Ham { get; set; }
public int Cheeze{ get; set; }
}
public class PepperoniPiza: BasePiza
{
public int Pepperoni { get; set; }
}
public class FourCheese: BasePiza
{
// foorcheese related properties
}
next, you want your factory to return the BasePizza class, and in the caller's code you handle the type of the pizza accordingly. if you're using c# 7.0 or higher, the pattern matching using the is will make life easier for you: expr is type varname
static void Main(string[] args)
{
PizzaMaker pizzamaker = new PizzaMaker();
BasePizza newPizza = pizzamaker.GetPizzaObject(PizzaMaker.PizzaNames.HamAndCheese);
if(newPizza is HamAndCheesePiza hamAndCheesePiza)
{
hamAndCheesePiza.Ham = 99;
hamAndCheesePiza.Cheese = 80;
}
// in the same way you treat other cases
}
Personally, I'd take a different tack altogether. I'd make a pizza a container to hold it's ingredients. I'd also take advantage of the collection initialization pattern (make a class enumerable, give it an appropriate void Add method, and you can initialize it like a Dictionary)
Something like this:
First some enums:
public enum Ingredient
{
Ham,
Pepperoni,
Pineapple,
etc,
}
public enum SauceType
{
Red,
White,
}
public enum PizzaSize
{
Personal,
Small,
Medium,
Large,
ExtraLarge,
}
then the Pizza class:
public class Pizza : IEnumerable<(Ingredient ingredient, int amountInGrams)>
{
private Dictionary<Ingredient, int> _ingredients = new Dictionary<Ingredient, int>();
private SauceType _sauceType;
private PizzaSize _size;
public Pizza(SauceType sauceType, PizzaSize size)
{
_sauceType = sauceType;
_size = size;
}
public void Add(Ingredient ingredient, int amountInGrams)
{
_ingredients.Add(ingredient, amountInGrams);
}
public IEnumerator<(Ingredient ingredient, int amountInGrams)> GetEnumerator()
{
foreach (var ingredient in _ingredients)
{
yield return (ingredient.Key, ingredient.Value);
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public static void TestPizza()
{
var newPizza = new Pizza(SauceType.Red, PizzaSize.Medium)
{
{Ingredient.Ham, 200},
{Ingredient.Pepperoni, 250}
};
foreach (var ingredient in newPizza)
{
Debug.WriteLine($"Ingredient: {ingredient.ingredient} - {ingredient.amountInGrams} grams");
}
}
}
If I run the TestPizza method, I end up with this in the debug output:
Ingredient: Ham - 200 grams
Ingredient: Pepperoni - 250 grams
You might also want to have a mechanism to have a recipe (if it's a medium pizza, and it has Ham, then it's 200 grams, 350 grams if it's "Double Meat" (but, I'll leave that up to you)).
As to your "Pizza Maker" factory, just build a class that has a set of recipes (roughly a Dictionary<string, (SauceType sauce, Dictionary<Ingredient, int>)>) and when someone asks for a "The Works" pizza, you look up the recipe, build a pizza the way I showed above (except by explicitly calling Add) and returns the result.
I like the C# language very much. I'm just playing around, and would never use the code below in production code. Obviously the compiler is fooled by the layout of the struct. But how come, that the string on the Super class can still be written and read in run-time? I would have expected some memory access violation. Inspecting the type during run time, it says it is of type Base, see the NoProblem() function execution. No Super class has been instantiated.
How is it able to function like this?
using System;
using System.Runtime.InteropServices;
namespace Fiddle
{
class Program
{
static void Main(string[] args)
{
var b = new Base
{
IntOnBase = 1
};
var overlay = new Overlay();
overlay.Base = b;
var super = overlay.Super;
var intValue = super.IntOnBase;
super.StringOnSuper = "my test string";
var stringValue = super.StringOnSuper;
super.NoProblem();
Expressions.Fiddle();
}
}
[StructLayout(LayoutKind.Explicit)]
public struct Overlay
{
[FieldOffset(0)]
public Super Super;
[FieldOffset(0)]
public Base Base;
}
public class Super : Base
{
public string StringOnSuper { get; set; }
public void NoProblem()
{
Console.WriteLine("You know, I am really a " + this.GetType().Name + " kind of class.");
}
}
public class Base
{
public int IntOnBase { get; set; }
}
}
Well you told the CLR to lay out the memory in advance by using StructLayout (I should caveat this saying this is based on my learning today after experimenting and reading the other answers suggested)
You can tell here that the CLR is not actually instantiating anything. This will throw a NPE. And you can play around with the the constructor on super. It isn't getting invoked, and won't.
Basically you are directly accessing memory, and since string, int etc are all built in types you are safely interacting with them. This should probably require more "intention" by the user, and the other commented questions are all pointing to this requiring an unsafe declaration.
class Program
{
static void Main(string[] args)
{
var b = new Base
{
IntOnBase = 1
};
var overlay = new Overlay();
overlay.Base = b;
var super = overlay.Super;
var intValue = super.IntOnBase;
super.StringOnSuper = 8;
var stringValue = super.StringOnSuper;
System.Diagnostics.Debug.WriteLine(stringValue);
super.NoProblem();
}
}
[StructLayout(LayoutKind.Explicit)]
public struct Overlay
{
[FieldOffset(0)]
public Super Super;
[FieldOffset(0)]
public Base Base;
}
public class NewClass
{
public string cat { get; set; }
}
public class Super : Base
{
private Super imNull;
public Super()
{
// imNull = new Super();
System.Diagnostics.Debug.WriteLine("well i get initialized...");
}
public int StringOnSuper { get; set; }
public void NoProblem()
{
System.Diagnostics.Debug.Write("You know, I am really a " + this.GetType().Name + " kind of class. But my super is " + imNull.ToString() );
}
}
public class Base
{
public int IntOnBase { get; set; }
}
I'm having trouble writing up some code. I'm not too sure where and how to write up the constructors and the accessors.
The activity I have to do is this:
Write 3 derived classes to allow a user to enter the details of three types of Vehicles with their attributes.
• Car (make, model, year, bodyType)
• Airplane (make, model, year, noEngines, engineType)
• Boat (make, model, year, length, hullType)
The 4th class is the base class Vehicle which contains the shared attributes and methods
Make all attributes either private (in derived classes) or protected (in base class) and write accessor methods for each attribute.
Write 2 constructors for each derived class. One with no arguments and the other which accepts the values of the attributes in the derived class as arguments.
Write a Console Application called Fleet.cs which creates and displays 2 of each Vehicle type
My code so far is as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication5
{
class Vehicle
{
static void Main(string[] args)
{
}
class Car
{
protected string make
{
get
{
return make;
}
set
{
make = value;
}
}
protected string model
{
get
{
return model;
}
set
{
model = value;
}
}
protected int year
{
get
{
return year;
}
set
{
year = value;
}
}
protected string bodyType
{
get
{
return bodyType;
}
set
{
bodyType = value;
}
}
public bool isInitialized;
public Car()
{
isInitialized = true;
}
}
}
class Airplane
{
protected string make
{
get
{
return make;
}
set
{
make = value;
}
}
protected string model
{
get
{
return model;
}
set
{
model = value;
}
}
protected int year
{
get
{
return year;
}
set
{
year = value;
}
}
protected int numEngines
{
get
{
return numEngines;
}
set
{
numEngines = value;
}
}
protected int engineType
{
get
{
return engineType;
}
set
{
engineType = value;
}
}
}
class Boat
{
protected string make
{
get
{
return make;
}
set
{
make = value;
}
}
protected string model
{
get
{
return model;
}
set
{
model = value;
}
}
protected string year
{
get
{
return year;
}
set
{
year = value;
}
}
protected string length
{
get
{
return length;
}
set
{
length = value;
}
}
protected string hullType
{
get
{
return hullType;
}
set
{
hullType = value;
}
}
}
}
First part the OOP principles
Classes:
A class is a construct that enables you to create your own custom
types by grouping together variables of other types, methods and
events. A class is like a blueprint. It defines the data and behavior
of a type. If the class is not declared as static, client code can use
it by creating objects or instances which are assigned to a variable.
The variable remains in memory until all references to it go out of
scope. At that time, the CLR marks it as eligible for garbage
collection. If the class is declared as static, then only one copy
exists in memory and client code can only access it through the class
itself, not an instance variable. For more information, see Static
Classes and Static Class Members (C# Programming Guide). Unlike
structs, classes support inheritance, a fundamental characteristic of
object-oriented programming. For more information, see Inheritance (C#
Programming Guide).
Also objects are instances of classes.
Inheritance:
Inheritance, together with encapsulation and polymorphism, is one of
the three primary characteristics (or pillars) of object-oriented
programming. Inheritance enables you to create new classes that reuse,
extend, and modify the behavior that is defined in other classes. The
class whose members are inherited is called the base class, and the
class that inherits those members is called the derived class. A
derived class can have only one direct base class. However,
inheritance is transitive. If ClassC is derived from ClassB, and
ClassB is derived from ClassA, ClassC inherits the members declared in
ClassB and ClassA.
Derived class:
A class that was created based on a previously existing class (i.e., base class). A derived class inherits all of the member variables and methods of the base class from which it is derived.
Also called a derived type.
Method:
A method (or message) in object-oriented programming (OOP) is a
procedure associated with an object class. An object is made up of
behavior and data. Data is represented as properties of the object and
behavior as methods. Methods are also the interface an object presents
to the outside world. For example a window object would have methods
such as open and close. One of the most important capabilities that a
method provides is method overriding. The same name (e.g., area) can
be used for multiple different kinds of classes. This allows the
sending objects to invoke behaviors and to delegate the implementation
of those behaviors to the receiving object. For example an object can
send an area message to another object and the appropriate formula
will be invoked whether the receiving object is a rectangle,circle,
triangle, etc.
Attributes and properties:
"Fields", "class variables", and "attributes" are more-or-less the
same - a low-level storage slot attached to an object. Each language's
documentation might use a different term consistently, but most actual
programmers use them interchangeably. (However, this also means some
of the terms can be ambiguous, like "class variable" - which can be
interpreted as "a variable of an instance of a given class", or "a
variable of the class object itself" in a language where class objects
are something you can manipulate directly.)
"Properties" are, in most languages I use, something else entirely -
they're a way to attach custom behaviour to reading / writing a field.
(Or to replace it.)
So if you want to categorize them they are OOP(Object Oriented Programming) principles.
Second part:
Write a Console Application called Fleet.cs which creates and displays
2 of each Vehicle type.
So one way of doing this is creating vehicles as hardcoded. The other way is to ask user for vehicle details with Console.Readline(). Main method could look something like this.
static void Main(string[] args)
{
Vehicle v1 = new Vehicle { Make = "test1", Model = "model1", Year = 1996 };
Vehicle v2 = new Vehicle { Make = "test2", Model = "model2", Year = 1997 };
Console.WriteLine(v1);
Console.WriteLine(v2);
...
}
And then you would override the ToString() method for each class. Like this:
public override string ToString()
{
return string.Format("Vehicle is {0} and of model {1} and is made in {2}.", make, model, year);
}
Here you also can use base.ToString() to get the data of upper (base) class in the derivided class.
EDIT 1: User input:
So if you want the user input you could make program like this:
static void Main(string[] args)
{
//input
Vehicle v1 = new Vehicle();
Console.Write("Enter the make of 1st vehicle: ");
v1.Make = Console.ReadLine();
Console.Write("Enter the model of 1st vehicle: ");
v1.Model = Console.ReadLine();
Console.WriteLine("Enter the year of manufacturing for 1st vehicle:");
v1.Year = int.Parse(Console.ReadLine());
//output
Console.WriteLine("The data for 1st vehicle: ");
Console.WriteLine(v1);
...
}
Even better would be to create Input method in the class and calling it from Main program. So code would not be repeating itself.
Finished program
Vehicle.cs
using System;
class Vehicle
{
string make, model;
int year;
public string Make { get { return make; } set { make = value; } }
public string Model { get { return model; } set { model = value; } }
public int Year { get { return year; } set { year = value; } }
public Vehicle()
{
make = model = "Unknown";
year = 0;
}
public Vehicle(string make, string model, int year)
{
this.make = make;
this.model = model;
this.year = year;
}
public virtual void GetFromInput()
{
Console.Write("Enter the make of vehicle: ");
Make = Console.ReadLine();
Console.Write("Enter the model of vehicle: ");
Model = Console.ReadLine();
Console.WriteLine("Enter the year of manufacturing for vehicle: ");
Year = int.Parse(Console.ReadLine());
}
public override string ToString()
{
return string.Format("Vehicle is {0} and of model {1} and is made in {2}.", make, model, year);
}
}
Car.cs
using System;
class Car : Vehicle
{
string bodyType;
public string BodyType { get { return bodyType; } set { bodyType = value; } }
public Car() : base()
{
bodyType = "Unknown";
}
public Car(string make, string model, int year, string bodyType) : base(make, model, year)
{
this.bodyType = bodyType;
}
public override void GetFromInput()
{
base.GetFromInput();
Console.Write("Enter body type for the car: ");
BodyType = Console.ReadLine();
}
public override string ToString()
{
return base.ToString() + string.Format("This vehicle is a car with body type of {0}.", BodyType);
}
}
Airplane.cs
using System;
class Airplane : Vehicle
{
int noEngines;
string engineType;
public int NumberOfEngines{ get { return noEngines; } set { noEngines = value; } }
public string EngineType { get { return engineType; } set { engineType = value; } }
public Airplane() : base()
{
noEngines = 0;
engineType = "Unknown";
}
public Airplane(string make, string model, int year, int noEngines, string engineType) : base(make, model, year)
{
this.noEngines = noEngines;
this.engineType = engineType;
}
public override void GetFromInput()
{
base.GetFromInput();
Console.Write("Enter the number of engines on an airplane: ");
NumberOfEngines = int.Parse(Console.ReadLine());
Console.Write("Enter the engine type for the airplane: ");
EngineType = Console.ReadLine();
}
public override string ToString()
{
return base.ToString() + string.Format("This vehicle is an airplane with {0} engines and engine type of {1}.", NumberOfEngines, EngineType);
}
}
Boat.cs
using System;
class Boat : Vehicle
{
int length;
string hullType;
public int Length { get { return length; } set { length = value; } }
public string HullType { get { return hullType; } set { hullType = value; } }
public Boat() : base()
{
length = 0;
hullType = "Unknown";
}
public Boat(string make, string model, int year, int length, string hullType) : base(make, model, year)
{
this.length = length;
this.hullType = hullType;
}
public override void GetFromInput()
{
base.GetFromInput();
Console.Write("Enter the length of the boat: ");
Length = int.Parse(Console.ReadLine());
Console.Write("Enter the hull type for the boat: ");
HullType = Console.ReadLine();
}
public override string ToString()
{
return base.ToString() + string.Format("This vehicle is a boat with length of {0} and hull type of {1}.", Length, HullType);
}
}
Fleet.cs
using System;
class Fleet
{
static void Main(string[] args)
{
Vehicle v1 = new Vehicle();
v1.GetFromInput();
Console.WriteLine(v1);
//... for the other vehicles
}
}
This can be achieved using class inheritance.
Each of your vehicle classes, need to inherit a common class that implements functionality need by 'all' vehicles, This class (Vehicle receptively), can then be used in C# to identify any type of vehicle class/type.
Instead of having a several classes where each class is solely responsible for a type of vechile, you can abstract out common functionality needed by each vehicle, and implement a class that exposes these common relationships:
using System;
public namespace CodeSpace {
public class Vehicle {
public Vehicle(Type type, string make, string model) {
Model = model;
Make = make;
Type = type;
}
public Type VehicleType { get; private set; }
public string Make { get; set; }
public string Model { get; set; }
}
public class Airplane : Vehicle {
public class Airplane(string make, string model) : base(typeof(Airplane), make, model) {
}
}
public class Boat : Vehicle {
public class Boat(string make, string model) : base(typeof(Boat), make, model) {
}
}
public class Car : Vehicle {
public class Car(string make, string model) : base(typeof(Car), make, model) {
}
}
class Program {
public static void Main(params string[] args ) {
var vehicles = new List<Vehicle>() {
new Boat("Canoe", "X2") as Vehicle,
new Boat("Raft", "A") as Vehicle,
new Car("Ford", "T") as Vehicle,
new Airplane("BMW", "Idk") as Vehicle,
};
foreach(var v in vehicles) {
Console.WriteLine(v.VehicleType.FullName);
}
}
}
}
Now all of your vehicles can be identified using one class that exposes all vehicles through a common interface.
I've been working on some electrical network simulation software (ElecNetKit). In electrical networks, sometimes it's convenient to work with single-phase models, sometimes in three-phase models.
As such, I would like to be able to represent one of the electrical network elements as:
class Bus
{
public Complex Voltage {set; get;} //single phase property
}
but simultaneously in a fashion so that the user can call Bus.Voltage.Phases[x], and expect a Complex for any valid integer x.
The Bus.Voltage property should map to Bus.Voltage.Phases[1] when treated as a Complex.
I've got two questions here:
Is this in violation of any OOP principles? I've got a feeling that it might be.
Is there a convenient way to represent this in C#?
In terms of representation, I've tried:
a class Phased<T> : T, but this is incompatible with the typing system, and
a class Phased<T> with a generic converter to type T, but the converter still needs to be invoked.
I'm aware that I can simply use something like:
public Dictionary<int,Complex> VoltagePhases {private set; get;}
public Complex Voltage {
set {VoltagePhases[1] = value;}
get {return VoltagePhases[1];}
}
but there's a lot of repetition once you start to do this for multiple properties, across multiple classes.
I would propose something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Numerics;
namespace Test
{
class PhaseList
{
private Dictionary<int, Complex> mPhases = new Dictionary<int, Complex>();
public Complex this[int pIndex]
{
get
{
Complex lRet;
mPhases.TryGetValue(pIndex, out lRet);
return lRet;
}
set
{
mPhases.Remove(pIndex);
mPhases.Add(pIndex, value);
}
}
}
class PhasedType
{
private PhaseList mPhases = new PhaseList();
public PhaseList Phases { get { return mPhases; } }
public static implicit operator Complex(PhasedType pSelf)
{
return pSelf.Phases[1];
}
public static implicit operator PhasedType(Complex pValue)
{
PhasedType lRet = new PhasedType();
lRet.Phases[1] = pValue;
return lRet;
}
}
class Bus
{
public PhasedType Voltage { get; set; }
}
class Program
{
static void Main(string[] args)
{
Bus lBus = new Bus();
lBus.Voltage = new Complex(1.0, 1.0);
Complex c = lBus.Voltage;
lBus.Voltage.Phases[1] = c;
c = lBus.Voltage.Phases[1];
}
}
}
Can you do something like this? This will work similar to your solution at the bottom but because of the generic class you are not repeating the code for each property.
class Program
{
static void Main(string[] args)
{
Collection<Complex> complex = new Collection<Complex>();
//TODO: Populate the collection with data
Complex first = complex.First;
Complex another = complex.Items[2];
}
}
public class Complex
{
// implementation
}
public class Collection<T> where T : class
{
public List<T> Items { get; set; }
public T First
{
get
{
return (Items.Count > 0) ? Items[1] : null;
}
set
{
if(Items.Count > 0)
Items[1] = value;
}
}
}
I don't know if the title is clear but basically I am trying to implement something like this:
public class Effect
{
public int InternalId ...
public void ResetName() ...
}
When ResetName is called, this will reset the name of the object to:
"Effect " + someIndex;
So if I have 5 instances of Effect, they will be renamed to:
"Effect 1"
"Effect 2"
"Effect 3"
...
So I have another method (ResetNames) in another manager/container type that calls ResetName for each instance. And right now I have to pass an integer to ResetName while keeping a counter myself inside ResetNames. But this feels not as clean and this prevents me from calling ResetName myself outside the manager class, which is valid.
How to do this better/cleaner?
As for the InternalId, it's just some id that stores the creation order for everything. So I can't just rely on these, because the numbers are large, like 32000, etc.
EDIT: Container ResetNames code:
int count = 1;
var effects = this.Effects.OrderBy ( n => n.InternalId );
foreach ( Effect effect in effects )
{
effect.ResetName ( count );
++count;
}
Have a manager class that handles the naming. It will also handle creation of the child class, and will embed a reference to itself. You can now call ResetName() on the child class, and it will have it's manager handle whatever logic needs to be done.
I'm not sure exactly what you want the results to be in various situations, but hopefully the following will be of some help:
public class Effect {
{
private EffectManager _manager;
public string Name {get;set;}
public Effect(EffectManager manager) {
_manager = manager;
}
public void ResetName() {
Name = _manager.GetNextName();
}
}
public class EffectManager {
private List<Effect> Effects;
private int currentIndex;
public Effect CreateEffect() {
var e = new Effect(this);
Effects.Add(e);
}
public string GetNextName() {
return "Effect " + currentIndex++;
}
public void ResetAllNames() {
currentIndex = 0;
foreach(var effect in Effects) {
effect.Name = GetNextName();
}
}
}
One of many possibilities: give your Effect class a public property Name, and in the method where you populate a list or array of Effect objects, assign the name. You can also give the Effect class an integer property and set the number, so that you can sort them, if you want.
public class Effect()
{
public string Name() { get; set; }
}
public class SomeClass()
{
private List<Effect> Effects;
public static void WhateverMethod()
{
for (var i = 0; i < Effects.Count; i++)
Effects[i].Name = "Effect " + (i + 1).ToString();
}
}
Are the names specific to all instance or to all instances in a given collection?
If the former you could do something like:
public class Effect
{
private static int _lastId;
public Effect()
{
InternalId = _lastId++;
}
public string Name
{
get { return "Effect" + InternalId.ToString(); }
}
public int InternalId ...
}
Namespace Diagnostics
<Conditional("DEBUG")> _
Public NotInheritable Class UniqueID
Private Shared _idBase As Integer
Private Sub New()
'keep compiler from creating default constructor
End Sub
Public Shared Function GetNext() As String
Return "ID" + System.Threading.Interlocked.Increment(_idBase).ToString("00")
End Function
End Class
End Namespace
Instead of having Name be a stored property, could you do something like this?
public class Effect
{
public int InternalId ...
public int Index;
public string BaseName;
public string Name
{
get
{
return BaseName + index;
}
}
}