Polymorphic Enums for state handling - c#

how do i handle Enums without using switch or if statements in C#?
For Example
enum Pricemethod
{
Max,
Min,
Average
}
... and i have a class Article
public class Article
{
private List<Double> _pricehistorie;
public List<Double> Pricehistorie
{
get { return _pricehistorie; }
set { _pricehistorie = value; }
}
public Pricemethod Pricemethod { get; set; }
public double Price
{
get {
switch (Pricemethod)
{
case Pricemethod.Average: return Average();
case Pricemethod.Max: return Max();
case Pricemethod.Min: return Min();
}
}
}
}
i want to avoid the switch statement and make it generic.
For a specific Pricemethod call a specific Calculation and return it.
get { return CalculatedPrice(Pricemethod); }
Wich pattern is to use here and maybe someone have a good implementation idea.
Searched already for state pattern, but i dont think this is the right one.

how do I handle enums without using switch or if statements in C#?
You don't. enums are just a pleasant syntax for writing const int.
Consider this pattern:
public abstract class PriceMethod
{
// Prevent inheritance from outside.
private PriceMethod() {}
public abstract decimal Invoke(IEnumerable<decimal> sequence);
public static PriceMethod Max = new MaxMethod();
private sealed class MaxMethod : PriceMethod
{
public override decimal Invoke(IEnumerable<decimal> sequence)
{
return sequence.Max();
}
}
// etc,
}
And now you can say
public decimal Price
{
get { return PriceMethod.Invoke(this.PriceHistory); }
}
And the user can say
myArticle.PriceMethod = PriceMethod.Max;
decimal price = myArticle.Price;

You could create an interface, and classes that implement it:
public interface IPriceMethod
{
double Calculate(IList<double> priceHistorie);
}
public class AveragePrice : IPriceMethod
{
public double Calculate(IList<double> priceHistorie)
{
return priceHistorie.Average();
}
}
// other classes
public class Article
{
private List<Double> _pricehistorie;
public List<Double> Pricehistorie
{
get { return _pricehistorie; }
set { _pricehistorie = value; }
}
public IPriceMethod Pricemethod { get; set; }
public double Price
{
get {
return Pricemethod.Calculate(Pricehistorie);
}
}
}
Edit: another way is using a Dictionary to map Funcs, so you don't have to create classes just for this (this code is based on code by Servy, who since deleted his answer):
public class Article
{
private static readonly Dictionary<Pricemethod, Func<IEnumerable<double>, double>>
priceMethods = new Dictionary<Pricemethod, Func<IEnumerable<double>, double>>
{
{Pricemethod.Max,ph => ph.Max()},
{Pricemethod.Min,ph => ph.Min()},
{Pricemethod.Average,ph => ph.Average()},
};
public Pricemethod Pricemethod { get; set; }
public List<Double> Pricehistory { get; set; }
public double Price
{
get
{
return priceMethods[Pricemethod](Pricehistory);
}
}
}

Related

Define material model with UnitsNet for material property storage

The goal is to build a metal database with UnitsNet with a defined pool of material properties.
These properties are to be represented in a DataGrid.
For example the PropertyDataGrid for copper:
Property
Value
Unit
Yield
40
MPa
Young modulus
70000
MPa
Density
2.6989
g/cm³
I'm not sure how to start.
First option: use an interface
using UnitsNet;
public interface IMetalProperty
{
public IQuantity Quantity { get; set; }
}
public class Density : IMetalProperty
{
public IQuantity Quantity { get; set; }
public override string ToString()
{
return Quantity.ToString();
}
}
public class Yield : IMetalProperty
{
public Pressure Quantity { get; set; }
public override string ToString()
{
return Quantity.ToString();
}
}
public class YoungModulus : IMetalProperty
{
public Pressure Value { get; set; }
public override string ToString()
{
return Quantity.ToString();
}
}
Than I can go ahead with a list or whatever:
var properties = new List<IMetalProperty>();
properties.Add(new Density { Quantity = UnitsNet.Density.FromGramsPerCubicCentimeter(2.6989) });
properties.Add(new Yield { Quantity = Pressure.FromMegapascals(40) });
Second option: use an abstract class
using UnitsNet;
public abstract class MetalProperty
{
public IQuantity Quantity { get; set; }
public override string ToString()
{
return Quantity.ToString();
}
}
public class Density : IMetalProperty
{
}
public class Yield : IMetalProperty
{
}
public class YoungModulus : IMetalProperty
{
}
The list works just as well:
var properties = new List<MetalProperty>();
properties.Add(new Density { Quantity = UnitsNet.Density.FromGramsPerCubicCentimeter(2.6989) });
properties.Add(new Yield { Quantity = Pressure.FromMegapascals(40) });
Questions:
Which is the better or the most typical way?
Is there a possibility to ensure the use of the right Units?
For example that it is restricted to add a metal property to the list: new Yield { Quantity = Pressure.FromGramsPerCubicCentimeter(40) }
How can I provide a list of all possible properties from which the user can choose one and define a new property for this metal?
Thanks for any help!

C# - Using subclasses to implement interfaces

I have the following interfaces
public interface IPrice
{
int Price { get; }
}
public interface IGear : IPrice
{
GearUpgrade Upgrades { get; }
}
and the following classes
public class GearUpgrade : IPrice
{
public int Price
{
get { return price; }
set { price = value; }
}
}
public class ArmorUpgrade : GearUpgrade
{
}
public class ShieldUpgrade : GearUpgrade
{
}
public class WeaponUpgrade : GearUpgrade
{
}
So when I try to implement an IGear like this...
public class Armor : IGear
{
private int price = 0;
public int Price { get => price; }
private ArmorUpgrade upgrades;
public ArmorUpgrade Upgrades
{
get { return upgrades; }
set { upgrades = value; }
}
}
I get the following error:
'Armor' does not implement interface member 'IGear.Upgrades'. 'Armor.Upgrades' cannot implement 'IGear.Upgrades' because it does not have the matching return type of 'GearUpgrade'.
I figured that if Upgrades is from a subclass of GearUpgrade, the interface should be fulfilled, but apparently it is not... Did I make a false assumption?
In order to implement the interface, the method signatures have to match exactly: C# doesn't apply covariance and contravariance implicitly.
Here's a simple fix to allow Armor to implement the IGear interface without messing with the class:
public class Armor : IGear
{
private int price = 0;
public int Price { get => price; }
private ArmorUpgrade upgrades;
public ArmorUpgrade Upgrades
{
get { return upgrades; }
set { upgrades = value; }
}
GearUpgrade IGear.Upgrades => this.Upgrades;
}

C#: Confusion about Interfaces, Implementation and Inheritance

I'm wondering about what's the way to go, if I need to publicate data-interfaces but want to use them internal with extended calculated properties. To make it clearer:
// The public interface
public interface IData
{
int Property { get; }
}
// The internal interface
internal interface IExtendedData : IData
{
int ExtendedProperty { get; }
}
// The assumed implementation of someone using my interface
public class Data : IData
{
public Data(int a)
{
Property = a;
}
public int Property
{
get;
private set;
}
public override string ToString()
{
return Property.ToString();
}
}
// My implementation
internal class ExtendedData : IExtendedData
{
public ExtendedData(int a)
{
Property = a;
}
public int Property
{
get;
private set;
}
public int ExtendedProperty
{
get
{
return 2 * Property;
}
}
public override string ToString()
{
return Property.ToString() + ExtendedProperty.ToString();
}
}
// publicated by me, for the person who uses my dll
public static class Calculations
{
public static int DoSomeCalculation(IData data, int parameter)
{
// This probably don't work, but maybe shows what I want to do
IExtendedData tempData = (ExtendedData)data;
return tempData.ExtendedProperty * parameter;
}
}
I'm realy frustrated, cause I feel like missing some basical programing skills.
You could solve this problem by implementing ExtendedData as a Wrapper for a class implementing IData
internal class ExtendedData : IExtendedData
{
private IData data;
public ExtendedData(IData data)
{
this.data = data;
}
public int Property
{
get { return data.Property; }
private set { data.Property = value; }
}
public int ExtendedProperty
{
get
{
return 2 * Property;
}
}
}
and use this in DoSomeCalculation like
IExtendedData tempData = new ExtendedData(data);
ExtendedData could inherit from Data:
class ExtendedData : Data
{...}
And for creation of a Data object you add a factory like so:
public class DataFactory
{
public IData CreateData()
{
return new ExtendedData();
}
}
User have to create all its Data objects by this factory. You can ensure it by making Data's constructor internal.
In your DLL you can then cast to ExtendedData.

C# Modifying the return of a custom data type at runtime

I've been teaching myself C#, and I'm just learning how to use custom data types. The program I'm writing produces a bunch of pairs of coordinate pairs. I thought it'd be a neat idea to create a data type that holds each set (x1, x2, y1, y2), along with a few other variables pertaining to that set. However, the program will produce more than one array of coordinates sets (different categories), so keeping track of things was still difficult. I then broke it down further into categories, and placed each category under a third type that acts as a third level, which is then put into a list.
Each "tier" of items has some properties specific to that tier, but prior to this roadblock I didn't have any need to swap data among the hierarchy. The problem arose when I realized that I needed to modify the coordinate pair sets using an offset, and each offset is specific to the parent data type. I can modify the get{} code to return the data plus the offset (I called it "skew"), but not if the offset is from outside the data type's class itself. I tried setting a value in the parent data type (even a public static one), but the child couldn't read it for some reason.
The only way I know how to make this work is by setting the property in each coordinate set, but there could be thousands of them. The value is unique to the parent, but all the children need to use it, so that seems wasteful, given that there will be a lot of other calculations going on. My other thought was to maintain an offset array, and add it to the places where the values are retrieved. But, that isn't as clean as containing it within the data type itself, and so it will add to the confusion. Is there another method of accomplishing this?
Here is how some of the code looks:
public class SlotData
{
private double _x1, _x2, _y1, _y2;
public double X1
{
get { return _x1; }
set { _x1 = value; }
}
public double X2
{
get { return _x2; }
set { _x2 = value; }
}
public double Y1
{
get { return _y1; }
set { _y1 = value; }
}
public double Y2
{
get { return _y2; }
set { _y2 = value; }
}
}
public class ClientInfo
{
public static double _skewX, _skewY;
public SlotGroup1 Group1
{
get;
set;
}
public SlotGroup2 Group2
{
get;
set;
}
public SlotGroup3 Group3
{
get;
set;
}
}
public class SlotGroup1
{
public SlotData Slot1
{
get;
set;
}
public SlotData Slot2
{
get;
set;
}
}
public class SlotData
{
private SlotData() { }
public SlotData(SlotGroupBase group)
{
this._group = group;
}
private SlotGroupBase _group;
public double X1 { get; set; }
public double X2 {get; set;}
public double Y1 {get; set;}
public double Y2 {get; set;}
public double NewX1
{
get
{
return _group.ClientInfo._skewX + X1;
}
}
}
public class ClientInfo
{
public double _skewX, _skewY;
public SlotGroup1 Group1 { get; set; }
}
public abstract class SlotGroupBase
{
private SlotGroupBase() { }
public SlotGroupBase(ClientInfo ci)
{
this._ci = ci;
}
private ClientInfo _ci;
public ClientInfo ClientInfo
{
get
{
return _ci;
}
}
}
public class SlotGroup1 : SlotGroupBase
{
public SlotGroup1(ClientInfo ci):base (ci) {}
public SlotData Slot1 { get; set; }
public SlotData Slot2 { get; set; }
}
static void Main(string[] args)
{
ClientInfo ci = new ClientInfo();
SlotGroup1 sg1 = new SlotGroup1(ci);
sg1.Slot1 = new SlotData(sg1);
sg1.Slot2 = new SlotData(sg1);
Console.ReadLine();
}
In your code you don't have either parent or descendant data types. So, members of some type couldn't be accessible to other types in any way other than you will have reference to an instance of object of some type.
But object-oriented programming could help you. In case if each from SlotGroupN types must have reference to ClientInfo, it would be worthwhile to have base class SlotGroupBase which will contain reference to ClientInfo. Also you should add to SlotData type reference to SlotGroupBase. In this case you will access your skews like
return _group.ClientInfo._skewX + X1;
Another good idea is to restrict yourself and other developers from creation SlotGroupN class instances without reference to ClientInfo, SlotData class item without reference to SlotGroup. To achieve this you should make default constructors private and add constructor with parameter ClientInfo
public SlotGroupBase(ClientInfo ci)
Extending you design ...
using System.Drawing;
public class SlotData
{
private PointF _one;
private PointF _two;
internal SizeF Skew {get; set;}
public PointF One
{
get
{
return PointF.Add(_one, Skew);
}
set {_one = value; }
}
public PointF Two
{
get
{
return PointF.Add(_two, Skew);
}
set {_two = value; }
}
}
public class SlotGroup : List<SlotData>
{
internal SizeF Skew
{
set
{
foreach(var slotData in this)
{
slotData.Skew = value;
}
}
}
}
public class ClientData : List<SlotGroup>
{
private SizeF _skew;
public SizeF Skew
{
get { return _skew; }
set
{
_skew = value;
foreach (var slotGroup in this)
{
slotGroup.Skew = value;
}
}
}
}
I could not think of anything more elegant that would work. Encapsulation dictates that contained classes cannot access the data of thier container and the code to override the the child accesors on the container classes would have been more cumbersome.

C# update a varying property on each item within a collection

I have this code (which is way simplified from the real code):
public interface IAmount
{
decimal Amount { get; set; }
}
public class SomeAmount : IAmount
{
public decimal Amount { get; set; }
}
public static void UpdateAmounts( this IEnumerable< IAmount > amounts, decimal totalAmount )
{
foreach ( IAmount amount in amounts )
amount.Amount = GetAmount();
}
public static decimal GetAmount()
{
return 12345m;
}
The code works great and the UpdateAmounts ExtensionMethod is used quite frequently throughout the application to apply a penny rounding routine (not like the one in Office Space!)
The problem is I do not like having an IAmount interface with a specific name of the column I need to set (Amount). In a new requirement, I need to update a database entity collection with this routine and the name of the property I need to update is "GrossAmount". Sometimes too it would be nice to update other writable decimal properties in a similar manner.
The problem is that it appears I cannot simple say amount.Field = GetAmount() where the .Field part deals with a different property on the entity. Is it possible somehow? I am not on C# 4.0, so using a dynamic type isn't possible for me yet.
You could do this in a more functional style, something like this:
public class Something
{
public decimal Amount { get; set; }
public decimal OtherAmount { get; set; }
}
public static void UpdateAmounts<T, U>(IEnumerable<T> items, Action<T,U> setter, Func<T, U> getter)
{
foreach (var o in items)
{
setter(o, getter(o));
}
}
public void QuickTest()
{
var s = new [] { new Something() { Amount = 1, OtherAmount = 11 }, new Something() { Amount = 2, OtherAmount = 22 }};
UpdateAmounts(s, (o,v) => o.Amount = v, (o) => o.Amount + 1);
UpdateAmounts(s, (o,v) => o.OtherAmount = v, (o) => o.OtherAmount + 2);
}
What about having a Dictionary-like interface ?
public interface IAmount {
decimal this[string fieldName] { get; set; }
}
Implementation is simply:
public class Money : IAmout {
private Dictionary<string, decimal> _dict;
public decimal this[string fieldName] {
get { return _dict[fieldName]; }
set { _dict[fieldName] = value; }
}
}
(of course, it requires some error checking)
Then, one can write:
Money m = new Money();
m["Amount"] = ...
or
m["GrossAmount"] = ...
Not as nice as dynamic, I agree.
public class SomeAmount : IAmount
{
decimal amount;
public decimal Amount
{
get{return this.amount;}
set{this.amount=value; }
}
}
Not sure how willing you are to screw with your entities, but...
public class SomeGrossAmount : IAmount
{
public decimal GrossAmount { get; set; }
decimal IAmount.Amount
{
get { return GrossAmount; }
set { GrossAmount = value; }
}
}
This hides the Amount implementation of your entity in any context that it's not directly used as an IAmount, while still allowing it to function as an IAmount.
You could hide the Field property, like this:
public interface IAmount
{
decimal Field
{ get; set; }
}
public class SomeAmount : IAmount
{
public decimal Amount
{ get; set; }
decimal IAmount.Field
{
get { return Amount; }
set { Amount = value; }
}
}
public class SomeGrossAmount : IAmount
{
public decimal GrossAmount
{ get; set; }
decimal IAmount.Field
{
get { return GrossAmount; }
set { GrossAmount= value; }
}
}
Casting the object to IAmount reveals the Field for your purposes. Otherwise, Field is hidden in the designer and Amount (or GrossAmount) is what you'll be working with.
You could also use reflection in order to apply your rounding on every decimal inside your type.
public static void UpdateAmounts( this IEnumerable< IAmount > amounts, decimal totalAmount )
{
foreach ( IAmount amount in amounts )
{
var myType = amount.GetType();
var myTypeProperties = myType.GetProperties();
foreach (PropertyInfo h_pi in myTypeProperties)
{
if (h_pi.Property_Type == typeof(decimal)) // or h_pi.Name == "Amount" || h_pi.Name == "GrossAmount"...
{
//DoStuff
}
}
}
amount.Amount = GetAmount();
}
there is better way to write that but I'm sure you get the point. Using reflection you could also get rid of the whole interface thing and simply go by reflection.
P.S. : Reflection is not the fastest way to go but it's an easy way to get runtime flexibility.
Let me know if that's what you wanted...
Or, when you do not mind using reflection (it is a bit slower): it is very powerful in combination with attributes. First, create an attribute used to mark the decimal property you need:
[AttributeUsage(AttributeTargets.Property,
Inherited = true, AllowMultiple = false)]
sealed class DecimalFieldAttribute : Attribute
{
public DecimalFieldAttribute()
{ }
}
Mark your field with the attribute, e.g.:
public class SomeGrossAmount
{
[DecimalField]
public decimal GrossAmount
{
get;
set;
}
}
Then use this method to set such a field:
public static void SetDecimalField(object obj, decimal value)
{
// Enumerate through all the properties to find one marked
// with the DecimalFieldAttribute.
PropertyInfo[] properties = obj.GetType().GetProperties();
PropertyInfo decimalfieldproperty = null;
foreach (PropertyInfo property in properties)
{
object[] attributes = property.GetCustomAttributes(typeof(DecimalFieldAttribute), true);
if (attributes.Length == 0)
continue;
// Check, or just break; when you'll not be making this error.
if (decimalfieldproperty != null)
throw new Exception("More than one property is marked with the DecimalFieldAttribute.");
// Found a candidate.
decimalfieldproperty = property;
}
// Check, or just assume that you'll not be making this error.
if (decimalfieldproperty == null)
throw new Exception("No property with the DecimalFieldAttribute found.");
// Set the value.
decimalfieldproperty.SetValue(obj, value, null);
}
I would suggest something like this:
public class Entity
{
public decimal Amount { get; set; }
public decimal OtherAmount { get; set; }
}
public static void Update<TEntity, TValue>(this IEnumerable<TEntity> entities, Func<TValue> valueGetter, Action<TEntity, TValue> valueSetter)
{
foreach (TEntity entity in entities)
{
TValue value = valueGetter.Invoke();
valueSetter.Invoke(entity, value);
}
}
public static decimal GetAmount()
{
throw new NotImplementedException();
}
public static decimal GetOtherAmount()
{
throw new NotImplementedException();
}
public static IEnumerable<Entity> GetEntities()
{
throw new NotImplementedException();
}
static void Main()
{
IEnumerable<Entity> entities = GetEntities();
entities.Update<Entity, decimal>(GetAmount, (entity, value) => entity.Amount = value);
entities.Update<Entity, decimal>(GetOtherAmount, (entity, otherValue) => entity.OtherAmount = otherValue);
}

Categories