I've created a class that represent a component. This component has a width,height,x-Coordinate,y-Coordinate, etc. When I manipulate the width,height,x, and y, I want to keep the logic within the class. But there is an interface object within the Component Class that has similar values. This interface can be used to talk to different types of CAD software. The Shape interface can be null though.
So my question is what would be the best approach for this? In the example below, when I change "Y", should I check for null in the shape interface? Or maybe the Component Class has event handlers and the Shape Interface should register to them. So what would be best practice for designing this approach and what would give the best performance?
Appreciate it!
public class Component
{
private double _y;
public IShape Shape { get; set; }
public string Name { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double X { get; set; }
public double Y
{
get => _y;
set
{
_y = value;
if (Shape != null) Shape.Y = value;
}
}
public void Update_Shape()
{
//used to update the Shape Interface after it is assigned
}
}
public interface IShape
{
string Name { get; set; }
double Width { get; set; }
double Height { get; set; }
double X { get; set; }
double Y { get; set; }
}
UPDATE: To give more details, my interface will be able to talk to Microsoft Visio, and AutoCad. They are only meant to be used as a visual representation of the data, the are not in control of how many shapes, or where they are positioned. So in my application, the user can move, or change width/height within the application. If they have Visio open at the time, I want it to update Visio shapes as well. If it isn't open, then it doesn't matter(it will end up being updated later on). Same goes for AutoCad.
The best practice in this situation depends on what your design goals are.
If you want to automatically update IShape and performance is critical then manually writing out your setters with a null check is going to give you both. Having an event that the IShape subscribes to causes you to have to invoke the event which is more expensive than checking null. And this has the benefit of keeping the mess inside the class as you only need to assign myComponent.X = 20;
Having an event has it's benefits. If you look up the Observer Pattern you can find lots of good reads on this. If you have more than one IShape that would subscribe to your Component, say from both Visio and AutoCad at the same time this would be the way to go.
Now in terms of performance, if you're update less than a few thousand components per second and you want cleaner code I would just call Update_Shape() when you want to synchronize the values. If you are assigning multiple values at the same time you can wrap them in an action that will automatically synchronize the values after it completes.
var c = new Component();
c.Shape = new Shape();
c.UpdateShapes(s => {
s.Height = 100;
s.Width = 100;
s.X = 5;
});
public class Component
{
public IShape Shape { get; set; }
public string Name { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double X { get; set; }
public double Y { get; set; }
public void UpdateShapes(Action<Component> update)
{
update(this);
SyncronizeShapes();
}
public void SyncronizeShapes()
{
if (Shape != null)
{
Shape.Name = Name;
Shape.Width = Width;
Shape.Height = Height;
Shape.X = X;
Shape.Y = Y;
}
}
}
Related
I am experimenting with a nested object class for an upcoming software project, in C#. I know how to do computed fields/properties within a class, at least as far as setting it programmatically with something like the date.
This is a little different. I am setting up a nested class like this:
string Test { get; set; }
List<Line> Detail { get; set; }
decimal Total {
get {
return TotalOf();
}
}
decimal TotalOf() {
var listQuery = this.Detail;
// This is where I'm trying to figure out how to do.
// I want the TotalOf function to return the sum of the
// Cost fields of the contained list items (Line is defined below).
// I will remove the "return 0;" eventually once
// I can figure out how to do the calculation.
return 0;
}
public class Line {
int indexOf { get; set; }
decimal Cost { get; set; }
}
That way, the field Total is automatically calculated rather than me having to compute it through the code consuming this class.
I have tried searching all over but I can't seem to find the right answer. I have plenty of time to do this, and worst case, I can just do it in the program consuming this class, but I thought I'd ask. When I hit the . after typing in this.Detail, the only aggregate function that comes up is Count.
I have tried to use the Detail.Sum function, hoping the Linq would bring up a lambda expression that I could then say "add up the Cost" but it won't come up.
I know this should be simple but I can't figure it out.
First, set access modifiers for Line properties like as public or other. Because, on default state it is private.
public class Line
{
public int indexOf { get; set; }
public decimal Cost { get; set; }
}
Then, set up root class like as LineCollection.
public class LineCollection
{
public class Line
{
public int indexOf { get; set; }
public decimal Cost { get; set; }
}
public string Test { get; set; }
public List<Line> Detail { get; set; }
public decimal Total { get; set; }
}
On LineCollection initialize default values for properties on constructor:
public class LineCollection
{
public class Line
{
public int indexOf { get; set; }
public decimal Cost { get; set; }
}
public string Test { get; set; }
public List<Line> Detail { get; set; }
public decimal Total { get; set; }
public LineCollection()
{
this.Test = string.Empty;
this.Detail = new List<Line>();
}
}
After this modify get/set accessors for Total property. I guess, property is read only and we not need to define set accessor.
public decimal Total
{
get
{
return this.Detail.Sum(x => x.Cost);
}
}
Code in get accessor automatically runs when we trying to get his value. Finally, we can run tests for checks.
LineCollection collection = new LineCollection();
collection.Detail.Add(new LineCollection.Line() { indexOf = 0, Cost = 43.3m });
collection.Detail.Add(new LineCollection.Line() { indexOf = 1, Cost = 23 });
collection.Detail.Add(new LineCollection.Line() { indexOf = 3, Cost = 56.21m });
Console.WriteLine(collection.Total.ToString());
It returns 122,51.
Think this method would work for you:
decimal TotalOf() {
return this.Detail.Select(line => line.Cost).Sum();
}
I believe this way also works:
decimal TotalOf() {
return this.Detail.Sum(line => line.Cost);
}
Hope this helps :)
I really struggle entitling this, but i'll try my best at explaining my point.
Say i have this :
List<IShape> Shapes = new List<IShape>();
public interface IShape {
dynamic shapeAttributes { get; set; }
};
public struct SquareAttributes {
float sizeOfSide;
};
public struct CircleAttributes {
float radius
};
public class Square : IShape {
SquareAttributes shapeAttributes { get; set; }
};
public class Circle : IShape {
CircleAttributes shapeAttributes { get; set; }
};
Shapes.Add(new Square());
Shapes.Add(new Circle());
How Do I make that situation work ? Here the "dynamic" keyword in IShape is not resolved when implemented in Square and Circle, but I'd still want to be able to define the right Type when implementing rather than using "dynamic" everywhere. Is there a right way to deal with this, with the ability re regroup all kind of Shapes in the same list? I hope this is clear.
I obviously simplified the whole thing to get straight to the point, but everything involved is far more complex and cannot really be fitted into a single large piece.
If your shapes attributes very different you can use System.Object as common type. But don't forget to check if you pass correct ShapeAttributes type to correct implementation of IShape, so I recommend to use set method instead of property setter:
Objects definition:
public interface IShape
{
object ShapeAttributes { get; }
Type ShapeAttributesType { get; }
void SetAttributes(object shapeAttributes);
}
public class Square : IShape
{
public object ShapeAttributes { get; private set; }
public Type ShapeAttributesType => typeof(SquareAttributes);
public void SetAttributes(object shapeAttributes)
{
// Check if passed correct type
if (shapeAttributes.GetType() != ShapeAttributesType)
throw new ArgumentException($"Argument type must be {ShapeAttributesType.FullName}", nameof(shapeAttributes));
ShapeAttributes = shapeAttributes;
}
}
public class Circle : IShape
{
public object ShapeAttributes { get; private set; }
public Type ShapeAttributesType => typeof(CircleAttributes);
public void SetAttributes(object shapeAttributes)
{
// Check if passed correct type
if (shapeAttributes.GetType() != ShapeAttributesType)
throw new ArgumentException($"Argument type must be {ShapeAttributesType.FullName}", nameof(shapeAttributes));
ShapeAttributes = shapeAttributes;
}
}
public struct SquareAttributes
{
public float SizeOfSide { get; set; }
}
public struct CircleAttributes
{
public float Radius { get; set; }
}
Usage example:
List<IShape> shapes = new List<IShape>();
var square = new Square();
square.SetAttributes(new SquareAttributes()
{
SizeOfSide = 4.1f
});
var circle = new Circle();
circle.SetAttributes(new CircleAttributes()
{
Radius = 2.12f
});
shapes.Add(square);
shapes.Add(circle);
foreach (var shape in shapes)
{
//Cast ShapeAttributes based on owner class type
switch (shape)
{
case Square s:
var size = ((SquareAttributes)s.ShapeAttributes).SizeOfSide;
Console.WriteLine($"Square.ShapeAttributes.SizeOfSide = {size}");
break;
case Circle c:
var radius = ((CircleAttributes)c.ShapeAttributes).Radius;
Console.WriteLine($"Circle.ShapeAttributes.Radius = {radius}");
break;
}
}
So I'm building a small game framework to reinforce abstract classes and interfaces. I've been building classes for some mechanics and I'm not sure how to deal with the final pieces.
Here's the class framework (with some miscellaneous methods removed):
public abstract class Ability
{
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual string Type { get; set; }
public virtual string Stat { get; set; }
public virtual float Scale { get; set; }
public virtual float MPCost { get; set; }
public virtual float SPCost { get; set; }
}
public class Attack : Ability
{
public float BaseDmg { get; set; }
public bool isUnblockable { get; set; }
public float GetDmg(int stat)
{
return BaseDmg * (1 + stat * Scale);
}
}
Now for the actual Attacks I want to create, should I instantiate like I have been?
public static class AllAttacks
{
//Physical Attacks
public static Attack slash = new Attack();
//Magical Attacks
public static Attack push = new Attack();
public static void Generate()
{
//Physical Attacks
slash.Name = "Slash";
slash.Description = "A simple but effective strike.";
slash.Type = "physical";
slash.Stat = "str";
slash.Scale = 0.1F;
slash.MPCost = 0;
slash.SPCost = 1;
slash.BaseDmg = 5;
slash.isUnblockable = false;
//Magical Attacks
push.Name = "Push";
push.Description = "A powerful telekinetic strike.";
push.Type = "magic";
push.Stat = "int";
push.Scale = 0.1F;
push.MPCost = 1;
push.SPCost = 0;
push.BaseDmg = 5F;
push.isUnblockable = false;
}
Or should I actually create a new inherited class for each unique item and then instantiate them in the Fight class? And if I do, should these be static or non-static?
public class Slash : Attack
{
//Code Here
}
Could anyone point me to best practices or what the most efficient method would be?
Typically there are two main reasons to define a new class: new behavior and/or new contract, that is changed implementation for the former reason or added new public members for the latter. Now considering your example I don't see changed contracts or behaviors for various types of attack (only changed state) so I don't see a reason to define new classes for them. From the readability standpoint the Generate method isn't optimal however - I'd create separate methods for different types of attack which would clearly denote what type of attack they create.
As for the instantiation aspects, if you aren't going to mutate your attack instances than get them created in the single place is pretty okay, otherwise you need to control the life cycle of every attack instance on the level where the instance is used.
Using DDD and following the clean architecture pattern and I'm a bit confused on where the ideal location is for configuring display properties for specific domain model ID's. That sounds confusing, I think I can best explain it with an example:
Here the domain model's business logic is simple: calculates a "scaled" value from an input, gain, and offset.
//Domain Model
public class Transducer
{
//Name is the ID
public string Name { get; set; }
public double Gain { get; set; }
public double Offset { get; set; }
public double RawValue { get; set; }
public double ScaledValue { get; private set; }
public double CalculateScaledValue(double RawValue)
{
ScaledValue = (Gain * RawValue) + Offset;
return ScaledValue;
}
}
We have a use case that coordinates user actions with the domain models and manages persistence. The details here an unimportant so I've only included an example interface:
//implementation of execution of business logic and persistance would go in the implentation, details left out for this example
public interface ITransducerUseCase
{
IEnumerable<string> GetAllTransducerNames();
void AddNewTransducer(string Name, double Gain, double Offset);
void SetGain(string Name, double Gain);
void SetOffset(string Name, double Offset);
void SetRawValue(string Name, double Raw);
double GetScaledValue(string Name);
}
The use case is used by the controller to coordinate the use cases with a view or other controller. This specific controller allows the viewing of all the transducer names and can change their Gain property.
public class Controller
{
ITransducerUseCase _TransducerUseCase;
//these are sent to the view to be displayed
public Dictionary<string, double> _transducerScaledValues = new Dictionary<string, double>();
public Controller(ITransducerUseCase TransducerUseCase)
{
_TransducerUseCase = TransducerUseCase;
//Get all the names and populate the dictionary to display.
foreach (var transducerName in _TransducerUseCase.GetAllTransducerNames())
_transducerScaledValues.Add(transducerName, _TransducerUseCase.GetScaledValue(transducerName));
}
//bound to the view
public string SelectedName { get; set; }
//bound to the view, a property for setting a new gain value
public double Gain { get; set; }
public void OnButtonClick()
{
//update the gain
_TransducerUseCase.ChangeGain(SelectedName, Gain);
//get the new scaled value
_transducerScaledValues[SelectedName] = _TransducerUseCase.GetScaledValue("PumpPressure");
}
}
That's the scaffolding for this question. Here is the new requirement:
We want to have an application level configuration setting for the
"number of decimal places" that is displayed for the ScaledValue of
Transducer on an identity basis. So a transducer with Id
"PumpPressure" could have a different value of DisplayRounding than
the transducer with the name "PumpTemperature".
This setting must be application wide (any time the value is
displayed, use this setting). This setting could also be used if the
ScaledValue was ever logged to a file, so it's a cross cutting
business need.
The solutions I've thought of:
Placing a property in the Domain Model and returning it through the layers to the view. This does not seem like a logical place because the DisplayRounding property does not have any relevance to the business logic.
public class Transducer
{
//This seems like an SRP violation
public int DisplayRounding { get; set; }
//Name is the ID
public string Name { get; set; }
public double Gain { get; set; }
public double Offset { get; set; }
public double ScaledValue { get; private set; }
public double CalculateScaledValue(double RawValue)
{
ScaledValue = (Gain * RawValue) + Offset;
return ScaledValue;
}
}
If not there, then where?
Could we put it in a separate Domain Model without any business logic? Persistence could be managed by the same Use Case class or a separate one.
public class TransducerDisplaySettings
{
public int Rounding { get; set; }
//plus other related properties
}
Pros: It separates out the concerns better than having one combined model.
Cons: The model does not have any business logic, is this okay?
We've also considered managing these settings completley on the outer layers with some sort of service.
Pros: No domain models without business logic
Cons: Would probably be tied to a specific framework?
Are are there more pros/cons I'm missing? Is one approach obviously better than the other? Is there an approach that I completely missed? Thanks!
The central decision you would have to make is whether the display rounding is an aspect of your applications business logic or "just an aspect of display".
In case you consider it as important for your business logic it should be modeled with your entities.
In case you consider it just as an aspect of "presenting values to the user" (so not relevant for business rules) it should be stored in a separate repository or service and then applied by the "presenter".
[table("NameTable")]
public class Transducer
{
//Name is the ID
[Key] //is Key from table
public string Name { get; set; }
public double Gain { get; set; }
public double Offset { get; set; }
public double RawValue { get; set; }
public double ScaledValue { get; private set; }
public double CalculateScaledValue(double RawValue)
{
ScaledValue = (Gain * RawValue) + Offset;
return ScaledValue;
}
}
I have a set of instance fields inherited from class G481Vars by object G481Var.
G481Vars G481Var = new G481Vars();
The values of the instance fields are assigned to through this function
private void AssignValuesG481()
{
HtmlInputText[] G481Inputs = new HtmlInputText[13] //Create an explicit array of type HtmlInputText to handle elements of input boxes on G481 tab.
{
G481Disp_Txt, G481IniVel_Txt, G481FinVel_Txt, G481Acc_Txt,
G481Time_Txt, G481Force_Txt, G481Mass_Txt, G481Weight_Txt,
G481Press_Txt, G481Dens_Txt, G481Energy_Txt, G481Area_Txt,
G481Vol_Txt
};
double[] G481List = new double[13] //Create an explicit array of type double that stores the instance fields of class G481Vars
{
G481Var.Disp, G481Var.IniVel, G481Var.FinVel, G481Var.Acc,
G481Var.Time, G481Var.Force, G481Var.Mass, G481Var.Weight,
G481Var.Press, G481Var.Dens, G481Var.Energy, G481Var.Area,
G481Var.Vol
};
for (int i = 0; i <= 12; i++) //Perform the iterative loop
{
if (G481Inputs[i].Value != "")
{
double.TryParse(G481Inputs[i].Value, out G481List[i]);
}
}
}
Where G481Vars is Defined as:
public class G481Vars
{
public double Disp { get; set; }
public double IniVel { get; set; }
public double FinVel { get; set; }
public double Acc { get; set; }
public double Time { get; set; }
public double Force { get; set; }
public double Mass { get; set; }
public double Weight { get; set; }
public double Press { get; set; }
public double Dens { get; set; }
public double Energy { get; set; }
public double Area { get; set; }
public double Vol { get; set; }
}
However when i try and access these instance fields from another function CalculateG481_Click They always return 0, even though they are assigned to before hand.
protected void CalculateG481_Click(object sender, EventArgs e)
{
AssignValuesG481();
TempInputDebugField.Value = Convert.ToString(G481Var.Disp); //This always returns 0 in the field, even though <>0 was put into the disp input field and assignvariables run.
}
When I put the TempInputDebugField code into the AssignValuesG481 function it returns the correct value. Any ideas on what is going on with the instance field?
Thanks for your help.
It seems like you think that setting the value of an element of G481List will forward that value on to the corresponding property of G481Var that was used to initialize the array. That is not true. all it does is change the values within the array.
You'll need to set the values of the instance explicitly. You could use reflection to set the properties dynamically, but with only 13 properties it would be much safer and cleaner to just set them explicitly:
G481Var.Disp = double.Parse(G481Inputs[0].Value)
G481Var.IniVel = double.Parse(G481Inputs[1].Value)
G481Var.FinVel = double.Parse(G481Inputs[2].Value)
G481Var.Acc = double.Parse(G481Inputs[3].Value)
G481Var.Time = double.Parse(G481Inputs[4].Value)
G481Var.Force = double.Parse(G481Inputs[5].Value)
G481Var.Mass = double.Parse(G481Inputs[7].Value)
G481Var.Weight = double.Parse(G481Inputs[8].Value)
G481Var.Press = double.Parse(G481Inputs[9].Value)
G481Var.Dens = double.Parse(G481Inputs[10].Value)
G481Var.Energy = double.Parse(G481Inputs[11].Value)
G481Var.Area = double.Parse(G481Inputs[12].Value)
G481Var.Vol = double.Parse(G481Inputs[13].Value)
From there you can use TryParse to better handle bad values, you can try using reflection to reduce duplicate code (at the expense of compile-time safety), etc. The point is to get something that works, then find ways to make it better. You can always go back to less "elegant" code if you get tired or stuck trying to refactor it.
Try this :
for (int i = 0; i <= 12; i++) //Perform the iterative loop
{
double val;
if (G481Inputs[i].Value != "")
{
double.TryParse(G481Inputs[i].Value, out val);
G481List[i] = val;
}
}
double is a valuetype, so when you parse the strings the values are stored only in the array. You will have to assign this values to G481Var properties:
double value;
if (double.TryParse(G481Disp_Txt.Value, out value)
G481Var.Disp = value;
Do this for each property and should works fine