Avoid multiple classes with only few different properties - c#

I have two classes which are close to the same, except for one variable type.The following example should demonstrate the problem.
class Customer
{
byte Reputation;
const byte MaximumReputation = 255;
int Data;
string MoreData;
Briefcase EvenMoreData;
public Customer(byte reputation, int data, string moreData, Briefcase evenMoreData)
{
Reputation = reputation;
Data = data;
MoreData = moreData;
EvenMoreData = evenMoreData;
}
public float Level()
{
return Reputation / MaximumReputation;
}
public string Information()
{
return Data.ToString() + ", " + MoreData + EvenMoreData.Id;
}
}
class CustomerDeluxe
{
ushort Reputation;
const byte MaximumReputation = 255;
int Data;
string MoreData;
Briefcase EvenMoreData;
public CustomerDeluxe(ushort reputation, int data, string moreData, Briefcase evenMoreData)
{
Reputation = reputation;
Data = data;
MoreData = moreData;
EvenMoreData = evenMoreData;
}
public float Level()
{
return Reputation / MaximumReputation;
}
public string Information()
{
return Data.ToString() + ", " + MoreData + EvenMoreData.Id;
}
}
Since Customers reputation won't exceed 255, I can store in a byte. In my application this field is a large array. That's why I would like to choose the smallest type possible. But there has to be another class for the few cases where the field can exceed a byte.
How can I "merge" these two classes?

Use generics:
public class BaseCustomer<TRep>
{
protected TRep Reputation;
}
public class CustomerDeluxe : BaseCustomer<ushort>
{
}
public class Customer : BaseCustomer<byte>
{
}
With generics, you are basically saying: "I am not sure what the type of TRep is but it will be manifested." A generic is said to be open when it is like above in BaseCustomer<TRep>. We will need to close it before we can use it. When we inherited it, then wevcloseed it with a specific type: in one instance we specified it to be ushort, in another we specified it to be byte.
And with some refactoring you can push most of the code to the BaseCustomer<T>:
public abstract class BaseCustomer<TRep>
{
protected TRep Reputation;
protected const byte MaximumReputation = 255;
int Data;
string MoreData;
Briefcase EvenMoreData;
public BaseCustomer(TRep reputation, int data, string moreData, Briefcase evenMoreData)
{
Reputation = reputation;
Data = data;
MoreData = moreData;
EvenMoreData = evenMoreData;
}
public abstract float Level();
public string Information()
{
return Data.ToString() + ", " + MoreData + EvenMoreData.Id;
}
}
public class CustomerDeluxe : BaseCustomer<ushort>
{
public CustomerDeluxe(ushort reputation, int data, string moreData, Briefcase evenMoreData)
: base(reputation, data, moreData, evenMoreData)
{
}
public override float Level()
{
return Reputation / MaximumReputation;
}
}
public class Customer : BaseCustomer<byte>
{
public Customer(byte reputation, int data, string moreData, Briefcase evenMoreData)
: base(reputation, data, moreData, evenMoreData)
{
}
public override float Level()
{
return Reputation / MaximumReputation;
}
}

class CustomerDeluxe : CustomerBase
{
ushort Reputation;
public override ushort GetReputation()
{
return Reputation;
}
}
class Customer : CustomerBase
{
byte Reputation;
public override ushort GetReputation()
{
return Reputation;
}
}
abstract class CustomerBase
{
const byte MaximumReputation = 255;
public abstract ushort GetReputation();
public float Level()
{
return GetReputation()/MaximumReputation;
}
}

Related

How to set fixed length to class attributes?

I am currently doing a project on B+ trees. I want to set my records with fix length attributes such that each record object will be of the same size (bytes) but I am not sure how to go about doing it.
Below is my code for the Record class.
public struct Record
{
private string tConst;
private double averageRating;
private int numVotes;
public Record(string tConst, double averageRating, int numVotes)
{
this.tConst = tConst;
this.averageRating = averageRating;
this.numVotes = numVotes;
}
public string getTConst()
{
return this.tConst;
}
public double getAverageRating()
{
return this.averageRating;
}
public int getNumVotes()
{
return this.numVotes;
}
public int getBytes()
{
return (
System.Text.ASCIIEncoding.ASCII.GetByteCount(this.tConst) +
System.Text.ASCIIEncoding.ASCII.GetByteCount(this.averageRating.ToString()) +
System.Text.ASCIIEncoding.ASCII.GetByteCount(this.numVotes.ToString())
);
}

A class to help access a chunk of memory

I need a class to help me access a chunk of memory
So far I have this
class ABSet
{
private byte[] _raw;
public ABSet(byte[] RawData)
{
_raw=RawData;
}
public double A
{
get
{
return BitConverter.ToDouble(_raw, 2);
}
}
public double B
{
get
{
return BitConverter.ToDouble(_raw, 10);
}
}
}
Now I would like to do something like this
class ABSetCollection
{
private byte[] _raw;
public ABSetCollcetion(byte[] RawData)
{
_raw=RawData;
}
public ABSet this[int index]
{
get
{
// This Part Is What I Want To Figure Out
}
}
}
I know I could put return new ABSet(_raw); but I feel like there must be a solution that requires less dynamic allocation.
P.S. The reason I want to use properties is because I am binding to them in my GUI
Rather than just accepting an array of bytes, change it so you get an offset too. Then you'll be able to get that to work.
class ABSet
{
public const int ABSetSize = 20; // or whatever the size
private readonly byte[] _data;
private readonly int _offset;
public ABSet(byte[] data, int offset = 0)
{
_data = data;
_offset = offset;
}
const int AOffset = 2;
public double A => BitConverter.ToDouble(_data, _offset + AOffset);
const int BOffset = 10;
public double B => BitConverter.ToDouble(_data, _offset + BOffset);
}
class ABSetCollection
{
private readonly byte[] _data;
private readonly int _offset;
public ABSetCollection(byte[] data, int offset = 0)
{
_data = data;
_offset = offset;
}
public ABSet this[int index] => new ABSet(_data, _offset + index * ABSet.ABSetSize);
}

methods from inherited class passed to base class

I have a feeling I'm doing this wrong. I'm new to abstract classes and such and have been reading tutorials for a little bit, but I can't figure out how to apply it to my situation. I think that my design might be faulty but I can't think of another way to do it. My company makes a few different computers and I need to be able to monitor the battery information. Although getting the information is not the problem, figuring out how to send the different commands to the base class to do what i need it to do. Say I want to get my cell 1 voltage. On one unit the command is 0x0418, on another it is 0x453. So in my information class I run a test to see what the model is. I have a Base class called battery that has a bunch of variables that are standard for each battery (cell voltage, charge ic, charging current etc etc) I then decided it would be good to make individual classes for each of my units that extends Battery.
Now my design of the classes I think is spot on (could be wrong as I am not good at abstraction and polymorphism). I have a panel that in the end would display the information that I get from the BatteryInformation class. something like Battery1Cell1Label.Text = batteryInfo.GetCell1(1); Battery2Cell1Label = batteryInfo.GetCell1(2).
So in my base class I guess I need a GetValue(byte command) (since it is a Embedded controller command to get each different types of information.) Maybe i should stop talking and just post my code of what i have and tell you the error that I have.
battery.cs
public abstract class Battery<T> //not sure that the <T> is right
{
public string Information { get; private set; }
public float Cell1 { get; private set; }
public float Cell2 { get; private set; }
public float Cell3 { get; private set; }
public float Cell4 { get; private set; }
public int FCC { get; private set; }
public bool ChargeIC { get; private set; }
public int StartCharge { get; private set; }
public int CurrentCharge { get; private set; }
public bool Exists { get; private set; }
protected internal void GetValue(byte command)
{
//Use Embedded controller to get said value
//ECPort.ReadEC(command);
//Testing Purposeses
Console.WriteLine(command);
}
}
Battery8800.cs
class Battery8800 : Battery<Battery8800>
{
public Battery8800() : base()
{
}
public void GetValue(BatteryCommands command)
{
base.GetValue((byte)command);
}
public enum BatteryCommands
{
Battery1VoltageHigh = 0x0402,
Battery1VoltageLow = 0x0403,
Batt1ChargeCurrentHigh = 0x0404,
Batt1ChargeCurrentLow = 0x0405,
Battery1MaxError = 0x0407,
Battery1RSOC = 0x0409,
Battery1FCCHigh = 0x040E,
Battery1FCCLow = 0x040F,
Battery1DCHigh = 0x0412,
Battery1DCLow = 0x0413,
Battery1Cell1High = 0x0418,
Battery1Cell1Low = 0x0419,
Battery1Cell2High = 0x041A,
Battery1Cell2Low = 0x041B,
Battery1Cell3High = 0x041C,
Battery1Cell3Low = 0x041D,
Battery1Cell4High = 0x041E,
Battery1Cell4Low = 0x041F,
PowerSource1 = 0x0420,
//many more commands for battery 2 etc etc
}
}
BatteryInformation.cs
class BatteryInformation
{
public Battery battery1; //error says it needs 1 type of argument
public Battery battery2; //error says it needs 1 type of argument
public BatteryInformation()
{
switch (UnitModel.GetModelEnum())
{
case UnitModel.DLIModel.DLI8300M:
battery1 = new Battery8300();
battery2 = new Battery8300();
break;
case UnitModel.DLIModel.DLI8400:
battery1 = new Battery8400();
battery2 = new Battery8400();
break;
case UnitModel.DLIModel.DLI8500:
battery1 = new Battery8500();
break;
case UnitModel.DLIModel.DLI8500P:
battery1 = new Battery8500P();
break;
case UnitModel.DLIModel.DLI8800:
battery1 = new Battery8800();
break;
case UnitModel.DLIModel.DLI9200:
battery1 = new Battery9200();
break;
default:
break;
}
//for testing purposes
battery1 = new Battery8800();
battery1.DoThis(Battery8800.BatteryCommands.Batt1ChargeCurrentHigh);
}
}
YEAH FOR DRAFT SAVING!!! the power just went out, and I didn't loose but 1 sentence!
so while my computer was turning back on I was thinking it might be better to do something like this in my battery panel class.
//in my timer_tick event
BatteryInformation.UpdateBatteries();
battery1Cell1Label.Text = BatteryInformation.Battery1.Cell1.ToString();
//etc etc
but i still need to get this working but am having a hard time figuring out how to do abstraction. Thank you for your time.
EDIT
I think i'm going about this the wrong way.
class Battery1_8400 : Battery
{
public override bool Update()
{
//TODO finish
Exists = GetValue((ushort)Commands.PowerSource) != 0xFF;
if (Exists)
{
Cell1 = GetValue((ushort)Commands.Cell1Low, (ushort)Commands.Cell1High) / 1000.0f;
Cell2 = GetValue((ushort)Commands.Cell2Low, (ushort)Commands.Cell2High) / 1000.0f;
Cell3 = GetValue((ushort)Commands.Cell3Low, (ushort)Commands.Cell3High) / 1000.0f;
FCC = GetValue((ushort)Commands.FCCLow, (ushort)Commands.FCCHigh);
Voltage = GetValue((ushort)Commands.VoltageLow, (ushort)Commands.VoltageHigh);
return true;
}
else
{
return false;
}
}
private enum Commands
{
PowerSource = 0x0480,
Charge = 0x0432,
RSOC = 0x0734,
DCLow = 0x0402,
DCHigh = 0x0403,
FCCLow = 0x0404,
FCCHigh = 0x0405,
MaxError = 0x0730,
Cell1Low = 0x0778,
Cell1High = 0x0779,
Cell2Low = 0x077C,
Cell2High = 0x077D,
Cell3Low = 0x0780,
Cell3High = 0x0781,
VoltageLow = 0x0438,
VoltageHigh = 0x0439,
ChargeCurrentLow = 0x0728,
ChargeCurrentHigh = 0x0729,
ChargeIC = 0x1A03,
}
}
I have 9 files that are ALL identical in terms of how the Update command works the difference is in the enum. The commands are slightly different per class. look at batter2_8400.cs 's enum
private enum Commands
{
PowerSource = 0x0480,
Charge = 0x04C2,
RSOC = 0x0834,
DCLow = 0x0492,
DCHigh = 0x0493,
FCCLow = 0x0494,
FCCHigh = 0x0495,
MaxError = 0x0830,
Cell1Low = 0x0878,
Cell1High = 0x0879,
Cell2Low = 0x087C,
Cell2High = 0x087D,
Cell3Low = 0x0880,
Cell3High = 0x0881,
VoltageLow = 0x04C8,
VoltageHigh = 0x04C9,
ChargeCurrentLow = 0x0828,
ChargeCurrentHigh = 0x0829,
ChargeIC = 0x1A04,
}
the update command is identical in that one as well as the other 7 files. Seems kinda bad design to me, but i'm stumped as to how I should do this. By the way this is what my classes look like after the one answer I was given and the few comments that was received.
your base class BatteryInformation should have abstract properties for each value you need to retrieve like so:
public abstract class BatteryInfo {
// int should be replaced with the actual data type of the value
public abstract int VoltageHigh { get; }
public abstract int VoltageLow { get; }
// etc. for each value you need
}
Then in your child class you implement each property
public class Battery8800 : BatteryInfo {
public override int VoltageHigh {
get {
int value;
// do code to retrieve value
return value;
}
}
}
In addition, I would provide a method somewhere that your UI can consume that looks like the following:
public IEnumerable<BatteryInfo> GetAllBatteryInfo() {
// get each battery
}
That way the UI does not need to worry about how the battery info is retrieved for each battery. That allows you to use one of the list or grid style controls to view the battery info.
In the end I think i figured out what I should do. It looks clean to me and seems to make sense. Maybe you can critique it?
public abstract class Battery
{
public string Information { get; set; }
public float Cell1 { get {return GetValue(Cell1Low, Cell1High) / 1000.0f;} }
public float Cell2 { get {return GetValue(Cell2Low, Cell2High) / 1000.0f;} }
public float Cell3 { get {return GetValue(Cell3Low, Cell3High) / 1000.0f;} }
public float Cell4 { get {return GetValue(Cell4Low, Cell4High) / 1000.0f;} }
public float Voltage { get {return GetValue(VoltageLow, VoltageHigh);} }
public int DC { get {return GetValue(DCLow, DCHigh);} }
public int FCC { get {return GetValue(FCCLow, FCCHigh);} }
//public bool ChargeIC { get {return } }
//public int StartCharge { get {return } }
//public int CurrentCharge { get {return } }
public bool Exists { get {return GetValue(PowerSource) != 0xFF} }
public int FCCPercent { get {return ((FCC * 100) / DC);} }
/// <summary>
/// Gets a value depending on the Embedded controller
/// </summary>
/// <param name="low">The low byte command to process</param>
/// <param name="high">The high byte command to process</param>
/// <returns></returns>
private int GetValue(ushort low, ushort high)
{
//Use Embedded controller to get said value
//ECPort.ReadEC(command);
//Testing Purposeses
var lowValue = ECPort.ReadEC(low);
var highValue = ECPort.ReadEC(high);
return (int)((highValue << 8) + lowValue);
}
private int GetValue(ushort command)
{
return (int)ECPort.ReadEC(command);
}
public abstract ushort PowerSource {get;}
public abstract ushort Charge{get;}
public abstract ushort RSOC{get;}
public abstract ushort DCLow{get;}
public abstract ushort DCHigh{get;}
public abstract ushort FCCLow{get;}
public abstract ushort FCCHigh{get;}
public abstract ushort MaxError{get;}
public abstract ushort Cell1Low{get;}
public abstract ushort Cell1High{get;}
public abstract ushort Cell2Low{get;}
public abstract ushort Cell2High{get;}
public abstract ushort Cell3Low{get;}
public abstract ushort Cell3High{get;}
public abstract ushort Cell4Low { get; }
public abstract ushort Cell4High { get; }
public abstract ushort VoltageLow{get;}
public abstract ushort VoltageHigh{get;}
public abstract ushort ChargeCurrentLow{get;}
public abstract ushort ChargeCurrentHigh{get;}
public abstract ushort ChargeIC{get;}
}
then on my sub classes that inherit it an example would be this
class Battery1_8400 : Battery
{
public override ushort PowerSource { get {return 0x0480;}}
public override ushort Charge { get {return 0x0432;}}
public override ushort RSOC { get {return 0x0734;}}
public override ushort DCLow { get {return 0x0402;}}
public override ushort DCHigh { get {return 0x0403;}}
public override ushort FCCLow { get {return 0x0404;}}
public override ushort FCCHigh { get {return 0x0405;}}
public override ushort MaxError { get {return 0x0730;}}
public override ushort Cell1Low { get {return 0x0778;}}
public override ushort Cell1High { get {return 0x0779;}}
public override ushort Cell2Low { get {return 0x077C;}}
public override ushort Cell2High { get {return 0x077D;}}
public override ushort Cell3Low { get {return 0x0780;}}
public override ushort Cell3High { get {return 0x0781;}}
public override ushort VoltageLow { get {return 0x0438;}}
public override ushort VoltageHigh { get {return 0x0439;}}
public override ushort ChargeCurrentLow { get {return 0x0728;}}
public override ushort ChargeCurrentHigh { get {return 0x0729;}}
public override ushort ChargeIC { get {return 0x1A03;}}
}
now all i have to do is edit the one file battery.cs if i need to make a change to it.

Help with building object model

Help me with building object model, please.
I need abstract class Unit representing each military unit in a game. There is Soldier, Tank, Jet and Bunker (children of Unit). Each of them has int properties Count and Defense, constructor with single int count parameter and one method GetTotalDefense.
My idea is following.
private abstract class Unit
{
private int Count { get; set; }
private const int Defense = 0;
protected Unit(int count)
{
Count = count;
}
public int GetTotalDefense()
{
return Count * Defense;
}
}
private class Tank : Unit
{
private const int Defense = 5;
}
Each unit has different Count and different Defense. Body of constructor and body of GetTotalDefense is always the same. What I need is in child class override Defense, because each unit has different. This property should be const, all instances of Tank (Soldier, ...) has same defense. Is there a possibility to inherit const property or each child needs its own const Defense property?
And here is an example I'd like to achieve.
Oh, there is also class Troop
public class Troop
{
private Soldier Soldiers { get; set; }
private Tank Tanks { get; set; }
private Jet Jets { get; set; }
private Fort Forts { get; set; }
public Troop(int soldiers, int tanks, int jets, int forts)
{
Soldiers = new Soldier(soldiers);
Tanks = new Tank(tanks);
Jets = new Jet(jets);
Forts = new Fort(forts);
}
public int GetTotalDefense()
{
return Soldiers.GetTotalDefense() + Tanks.GetTotalDefense() + Jets.GetTotalDefense() + Forts.GetTotalDefense();
}
}
Also, feel free to suggest better solution, thanks.
PS: I'm really strict about access modifiers, so be precise in your examples, thank you.
You can't really use a const but you can make a readonly property also are you sure you want the classes to be private and not internal or public?
public abstract class Unit {
protected Unit(int count) {
Count=count;
}
protected int Count { get; private set; }
protected abstract int Defense {get;}
public int TotalDefense {
get { return Count*Defense; }
}
}
public class Tank : Unit {
public Tank(int count) : base(count) {}
protected override int Defense {
get { return 5; }
}
}
public class Troop {
private Unit[] Troops;
public Troop(int soldiers, int tanks, int jets, int forts) {
Troops = new Unit[] {
new Soldier(soldiers),
new Tank(tanks),
new Jet(jets),
new Fort(forts)
};
}
// The using System.Linq you can do
public int TotalDefense {
get { return Troops.Sum(x=>x.TotalDefense);}
}
}
Although this solution does not use const, it achieves what you want:
internal abstract class Unit
{
private int Count { get; set; }
private int Defense { get; set; }
public int TotalDefense { get { return Count * Defense; } }
protected Unit(int defense, int count)
{
Defense = defense;
Count = count;
}
}
internal class Tank : Unit
{
protected Tank(int count)
: base(5, count) // you can use a const variable instead of 5
{
}
}
Or maybe this is more suitable:
internal abstract class Unit
{
private int Count { get; set; }
public abstract int Defense { get; }
public int TotalDefense { get { return Count * Defense; } }
protected Unit(int count)
{
Count = count;
}
}
internal class Tank : Unit
{
override public int Defense { get { return 5; } }
protected Tank(int count) : base(count)
{
}
}
What you're looking for is actually readonly. Also, since Defense is used in subclasses, you need to make it protected.
private abstract class Unit
{
private int _Count;
protected readonly const int Defense;
public int TotalDefense
{ get { return Count * Defense; } }
protected Unit (int count, int defense)
{
Defense = defense;
_Count = count;
}
}
private class Tank : Unit
{
public Tank (int Count)
: base (Count, 5)
{ }
}
public class Troop
{
public IEnumerable<Unit> Units { get; protected set; }
public Troop (int soldiers, int tanks, int jets, int forts)
{
Troops = new Unit[]
{
new Soldier (soldiers),
new Tank (tanks),
new Jet (jets),
new Fort (forts)
}
}
}
maybe something like this (but this is in java)
abstract class Unit {
Unit(int defense,int count) {
this.defense = defense;
this.count=count;
}
final int defense;
int count;
}
class Soldier extends Unit {
Soldier(int count) {
super(1,count);
}
}
class Tank extends Unit {
Tank(int count) {
super(5,count);
}
}
public class Main {
public static void main(String[] args) {
Unit[] units = { new Soldier(2), new Tank(3) };
for(Unit unit:units)
System.out.println(unit.count+" "+unit.defense);
}
}

C#: Pass derived class as parameter

I have a base class that does calculations on image sizes. I'm deriving a class from that and have predefined image sizes that will be used in my code. While what I have works, I have a strong feeling that I'm not doing it properly.
Ideally, I'd like to just pass DerviedClass.PreviewSize as the parameter to GetWidth without having to create an instance of it.
class Program
{
static void Main(string[] args)
{
ProfilePics d = new ProfilePics();
Guid UserId = Guid.NewGuid();
ProfilePics.Preview PreviewSize = new ProfilePics.Preview();
d.Save(UserId, PreviewSize);
}
}
class ProfilePicsBase
{
public interface ISize
{
int Width { get; }
int Height { get; }
}
public void Save(Guid UserId, ISize Size)
{
string PicPath = GetTempPath(UserId);
Media.ResizeImage(PicPath, Size.Width, Size.Height);
}
}
class ProfilePics : ProfilePicsBase
{
public class Preview : ISize
{
public int Width { get { return 200; } }
public int Height { get { return 160; } }
}
}
It seems to me that you want a more flexible implementation of ISize - having an implementation which always returns the same value seems fairly pointless. On the other hand, I can see that you want an easy way of getting the size that you always use for a preview. I would do it like this:
// Immutable implementation of ISize
public class FixedSize : ISize
{
public static readonly FixedSize Preview = new FixedSize(200, 160);
private readonly int width;
private readonly int height;
public int Width { get { return width; } }
public int Height { get { return height; } }
public FixedSize(int width, int height)
{
this.width = width;
this.height = height;
}
}
You could then write:
ProfilePics d = new ProfilePics();
Guid userId = Guid.NewGuid();
d.Save(userId, FixedSize.Preview);
This would reuse the same instance of FixedSize whenever you called it.
There are a few ways that you could do this, depending on your needs. I would look at doing a different interface, setup. Something like this.
public interface ISizedPics
{
int Width {get; }
int Height {get; }
void Save(Guid userId)
}
public class ProfilePics, iSizedPics
{
public int Width { get { return 200; } }
public int Height { get { return 160; } }
public void Save(Guid UserId)
{
//Do your save here
}
}
Then, with this done, you could actually work with it like this.
ISizedPics picInstance = new ProfilePics;
Guid myId = Guid.NewGuid();
picInstance.Save(myId);
This is just one way of doing it, I like this way, as you can easily create a factory class around this that helps you declare the instances as needed.

Categories