Performing calculations on properties generically and fast - c#

The goal is to create a method which generically performs calculations on a property of a list of objects in a performant manner. Below is the entire test code:
using System;
using System.Collections.Generic;
namespace TestApp
{
public class Minute
{
public DateTime DateTimeUtc { get; set; }
public float Source { get; set; }
public float Mult2 { get; set; }
public float Mult3 { get; set; }
public float Mult4 { get; set; }
}
class Program
{
public static List<Minute> Minutes = new List<Minute>();
static void Main(string[] args)
{
for (int i = 1; i < 10000000; i++)
{
Minute newMinute = new Minute();
newMinute.Source = i;
Minutes.Add(newMinute);
}
GenerateMult2(Minutes, 2); // 160 ms
GenerateMult2Generic(Minutes, typeof(Minute), nameof(Minute.Source), nameof(Minute.Mult2),2); // 4300 ms
}
public static void GenerateMult2(List<Minute> Minutes, int multiplier)
{
for (int i = 0; i < Minutes.Count; i++)
{
// Simplified calculation, there will eventually be a lot more code that goes here!
Minutes[i].Mult2 = Minutes[i].Source * multiplier;
}
}
public static void GenerateMult2Generic<T>(List<T> SourceList, Type ContainerType, string propNameSource, string propNameMult, int multiplier)
{
var propertyInfoSource = ContainerType.GetProperty(propNameSource);
var propertyInfoMult = ContainerType.GetProperty(propNameMult);
foreach (T item in SourceList)
{
float sourceValue = (float)propertyInfoSource.GetValue(item);
propertyInfoMult.SetValue(item, sourceValue * multiplier);
}
}
}
}
In this test app there is a method called GenerateMult2, whose purpose is to make some calculation on one of the properties in a list of Minute objects. This method works fine and is fast. The problem is that the method is too specific. If I wanted to do the same calculations on the properties Mult3 and Mult4, I would need to make a separate method for each of these properties, which is too much duplicated code. I want to make this method more generic, which is, I want the method to accept lists of other types as well, for example a list of Day objects or Second objects. Furthermore, I want to tell the method which property to perform the calculations on.
So I've made an attempt at creating a generic method called GenerateMult2Generic. This method performs the exact same calculation as the GenerateMult2 method, and is multipurpose, which is what I want. The huge disadvantage is that it's way too slow due to the reflections.
How can the GenerateMult2 method be made in a generic fashion, but with a performance penalty of no more than 5%?
Update with solution
Having studied the answers here, the best is one that was given by Ed Plunkett, but somehow was removed. Therefore, I'm posting the original code updated with the ideas from that answer:
using System;
using System.Collections.Generic;
using System.Linq;
namespace TestApp
{
public class Minute : BaseTime
{
public float MovingAverageFast { get; set; }
public float MovingAverageSlow { get; set; }
public float RsiFast { get; set; }
public float RsiSlow { get; set; }
}
public class Day : BaseTime
{
public float MovingAverageFast { get; set; }
public float MovingAverageSlow { get; set; }
public float RsiFast { get; set; }
public float RsiSlow { get; set; }
}
public class BaseTime
{
public DateTime DateTimeUtc { get; set; }
public float Source { get; set; }
}
class Program
{
public static List<Minute> Minutes = new List<Minute>();
public static List<Day> Days = new List<Day>();
static void Main(string[] args)
{
Minutes = Enumerable.Range(1, 10000000).Select(n => new Minute { Source = n }).ToList();
Days = Enumerable.Range(1, 10000000).Select(n => new Day { Source = n }).ToList();
// Generating data for Minutes
GenerateMovingAverage(Minutes, 100, (m, value) => ((Minute)m).MovingAverageFast = value);
GenerateMovingAverage(Minutes, 500, (m, value) => ((Minute)m).MovingAverageSlow = value);
GenerateRsi(Minutes, 60, (m, value) => ((Minute)m).RsiFast = value);
GenerateRsi(Minutes, 250, (m, value) => ((Minute)m).RsiSlow = value);
// Generating data for Days
GenerateMovingAverage(Days, 8, (d, value) => ((Day)d).MovingAverageFast = value);
GenerateMovingAverage(Days, 45, (d, value) => ((Day)d).MovingAverageSlow = value);
GenerateRsi(Days, 5, (d, value) => ((Day)d).RsiFast = value);
GenerateRsi(Days, 21, (d, value) => ((Day)d).RsiSlow = value);
}
public static void GenerateMovingAverage(IEnumerable<BaseTime> BaseTimeObjects, int Period, Action<BaseTime, float> setter)
{
foreach (var BaseTimeObject in BaseTimeObjects)
{
float newValue;
newValue = BaseTimeObject.Source * Period; // pseudo calculation for generating moving average
setter(BaseTimeObject, newValue);
}
}
public static void GenerateRsi(IEnumerable<BaseTime> BaseTimeObjects, int Period, Action<BaseTime, float> setter)
{
foreach (var BaseTimeObject in BaseTimeObjects)
{
float newValue;
newValue = BaseTimeObject.Source / Period; // pseudo calculation for generating rsi
setter(BaseTimeObject, newValue);
}
}
}
}
The key idea here is setting the property via an Action in the caller. With this solution, the calculation methods are reused for any object and any property with good performance.

In addition to what #iSR5 wrote, you might consider using a factory design pattern, making classes that do the actual calculations. This would be good if you don't know what you actually need to do until run time.
public interface IMultiValueGenerator
{
void GenerateValue(ITimeMulti multi, int multiplier);
}
public class Multi2Generator : IMultiValueGenerator
{
public void GenerateValue(ITimeMulti multi, int multiplier)
{
multi.Mult2 = multi.Source * multiplier;
}
}
public static class MultiGeneratorFactory
{
public static IMultiValueGenerator GetGenerator(...)
{
if (condition)
return new Multi2Generator();
// etc
}
}

Not sure if I've got the full picture here, but from my understanding, you'll need to have an interface with a base class. The interface is the one that you'll use to define the object, while the base class is the container for all common operations, which can be inhered by the class children. Then, you can create child class (as many as you want) and inherit the base class. The child class will have its required properties, methods, and logic if needed.
Enough talking, let's take it in code :
interface ITimeMulti
{
DateTime DateTimeUtc { get; set; }
float Source { get; set; }
// will be used for number of available properties.
int MultCount { get; }
// the main method for generating the multipliers.
void Generate(int multNumber, int multiplier);
}
Simple ? let's now create the base class :
public class TimeMulti : ITimeMulti
{
public DateTime DateTimeUtc { get; set; }
public float Source { get; set; }
// Using Dictionary will be much faster than Reflection
protected static Dictionary<string, float> Multipliers { get; set; }
// Number of Properties (the set should be within the derived classes)
public int MultCount { get; protected set; }
// This is a restriction to create this instance from the derived classes only
private TimeMulti() { }
// for derived classes
protected TimeMulti(int multCount)
{
// Should be in this constructor only
Initiate(multCount);
}
// This is the main method to generate the multiplication part.
public void Generate(int multNumber, int multiplier)
{
if (multNumber == 0)
{
Multipliers["Mult"] = Source * multiplier;
}
else if (Multipliers.ContainsKey("Mult" + multNumber))
{
// store the value in the dictionary (this is for reference)
Multipliers["Mult" + multNumber] = SetMult(multNumber, Source * multiplier);
}
else
{
throw new NullReferenceException();
}
}
// On new instance, this will fired, which will setup the dictionary
protected void Initiate(int numberOfMultipliers)
{
// Ensure you have an active instance of the dictionary
if (Multipliers == null)
Multipliers = new Dictionary<string, float>();
// Ensurance
if(numberOfMultipliers > 0)
{
MultCount = numberOfMultipliers;
for (int x = 1; x <= numberOfMultipliers; x++)
if (!Multipliers.ContainsKey("Mult" + x))
Multipliers.Add("Mult" + x, 0);
}
else
{
throw new ArgumentOutOfRangeException();
}
}
// this is where we will replace Reflection, here is just returning the multValue
// we will override it on the derived classes
protected virtual float SetMult(int MultNumber, float multValue) => multValue;
}
Now, the derived class
public class Minute : TimeMulti
{
public float Mult1 { get; set; }
public float Mult2 { get; set; }
public float Mult3 { get; set; }
public float Mult4 { get; set; }
// MultCount = 4
public Minute(): base(4) { }
// This method will set the value of the property using switch statment, with this, you will avoid Reflection.
protected override float SetMult(int multNumber, float multValue)
{
switch (multNumber)
{
case 1:
Mult1 = multValue;
break;
case 2:
Mult2 = multValue;
break;
case 3:
Mult3 = multValue;
break;
case 4:
Mult4 = multValue;
break;
}
return multValue;
}
}
Now, you can do this :
class Program
{
// Create List with type of the ITimeMulti interface
public static List<ITimeMulti> Minutes = new List<ITimeMulti>();
static void Main(string[] args)
{
// Generate a sample
for (int i = 1; i < 10000000; i++)
Minutes.Add(new Minute() { Source = i});
// Calculate
GenerateMultipliers(Minutes, 1, 2);
}
public static void GenerateMultipliers(List<ITimeMulti> source, int multNumber, int multiplier)
{
for (int i = 0; i < source.Count; i++)
{
source[i].Generate(multNumber, multiplier);
}
}
}
If you want to create a new derived class :
public class Day : TimeMulti
{
// Properties
public float Mult1 { get; set; }
// Constructor
public Day(): base(1) { }
// This method to map the values to the properties
protected override float SetMult(int multNumber, float multValue)
{
switch (multNumber)
{
case 1:
Mult1 = multValue;
break;
}
return multValue;
}
}
This is just an example to give you a new ideas, you can do your own magic. I wouldn't go with Mult1 ...etc. I would go with a unique and a descriptive names.
Updated :
You can improve the performance of your updated code, by gathering all common properties in the base and make use of virtual and override if you want to have something override-able in a child class. Or, use interface and struct instead of classes. Also, instead of using IEnumerable use Array this would improve your performance as well.
public class BaseTime
{
// shared proprties
public DateTime DateTimeUtc { get; set; }
public float Source { get; set; }
public float MovingAverageFast { get; set; }
public float MovingAverageSlow { get; set; }
public float RsiFast { get; set; }
public float RsiSlow { get; set; }
}
public class Minute : BaseTime
{
// add your custom code for Minute
// No need for recreating them, since it's already inherited from the base
}
public class Day : BaseTime
{
// add your custom code for Day
// No need for recreating them, since it's already inherited from the base
}
class Program
{
public static BaseTime[] Minutes;
public static BaseTime[] Days;
static void Main(string[] args)
{
Minutes = Enumerable.Range(1, 10000000).Select(n => (BaseTime) new Minute { Source = n }).ToArray();
Days = Enumerable.Range(1, 10000000).Select(n => (BaseTime) new Day { Source = n }).ToArray();
// Generating data for Minutes
GenerateMovingAverage(Minutes, 100, (m, value) => m.MovingAverageFast = value);
GenerateRsi(Minutes, 60, (m, value) => m.RsiFast = value);
GenerateRsi(Minutes, 250, (m, value) => m.RsiSlow = value);
// Generating data for Days
GenerateMovingAverage(Days, 8, (d, value) => d.MovingAverageFast = value);
GenerateMovingAverage(Days, 45, (d, value) => d.MovingAverageSlow = value);
GenerateRsi(Days, 5, (d, value) => d.RsiFast = value);
GenerateRsi(Days, 21, (d, value) => d.RsiSlow = value);
}
public static void GenerateMovingAverage(BaseTime[] BaseTimeObjects, int Period, Action<BaseTime, float> setter)
{
foreach (var BaseTimeObject in BaseTimeObjects)
{
setter(BaseTimeObject, BaseTimeObject.Source * Period);
}
}
public static void GenerateRsi(BaseTime[] BaseTimeObjects, int Period, Action<BaseTime, float> setter)
{
foreach (var BaseTimeObject in BaseTimeObjects)
{
setter(BaseTimeObject, BaseTimeObject.Source / Period);
}
}
}

Related

C# Interface: extracting additional public property value (not part of interface) from a concrete class

Code sample to begin with:
internal class ClubHouse : ILeasable
{
public int Id { get; set; }
public int AreaInSquareFeet { get; set; }
}
public class Parking : ILeasable
{
public int Id { get; set; }
public int CarCapacity { get; set; }
}
internal interface ILeasable
{
int Id { get; set; }
}
class LeasableRepository
{
private List<ILeasable> _leasable = new List<ILeasable>()
{
new ClubHouse() {Id = 208, AreaInSquareFeet = 7500 },
new ShowRoom(){ Id = 202, AreaInSquareFeet = 4000 },
new Parking() {Id = 504, CarCapacity = 4},
};
private Dictionary<int, ILeasable> _leasableDictionary = new Dictionary<int, ILeasable>();
public LeasableRepository()
{
_leasableDictionary = _leasable.ToDictionary(x => x.Id, x => x);
}
public ILeasable GetLeasable(int id)
{
if (_leasableDictionary.ContainsKey(id)) return _leasableDictionary[id];
return null;
}
}
public class ChargeCalculatingFacade
{
LeasableRepository leasableRepository = new LeasableRepository();
public void ShowLeasingCharges(int id)
{
var leasable = leasableRepository.GetLeasable(id);
var leasingCharge = GetLeasingCharges(leasable);
}
private int GetLeasingCharges(ILeasable leasable)
{
// This is not possible as I can't be sure that leasable is ClubHouse
var property = (ClubHouse) leasable;
var areaInSquareFeet = property.AreaInSquareFeet;
return areaInSquareFeet * 10;
}
}
Now, in class ChargeCalculatingFacade class, in method ShowLeasingCharges(int id), based on the id, I called GetLeasable(int id) which returns one of the implementation of ILeasable. However it return as an interface ILeasable.
I pass that ILeasable to a private method GetLeasingCharges(leasable) to calculate the leasing charges based on the AreaInSquareFeet.
Now, leasable parameter is just ILeasable, which has just "Id" property available. Now how to identify which concreat class implementation is passed as parameter, I can cast it to get AreaInSquareFeet like this
var property = (ClubHouse) leasable;
var areaInSquareFeet = property.AreaInSquareFeet;
But the above code is not posible as I am not sure if the leasable is ClubHouse as it just picks leasable from a dictionary based on Id.
All class does not have the same additional property. For instance, Parking has additional property as "CarCapacity". I have 10 such classes, now cannot put 10 if logic to check if the interface is of required class type.
I wonder if some design pattern or some SOLID principle can simplify the design.
I have following questions:
How do I get the areaInSquareFeet in such case
Is this a good practice to have an interface with few methods and properties and again have additional public methods or properties in concreate class.
Note: I do not want to use reflection. I would like to change a design in case without reflection is not possible. Any design suggestions? Any desing pattern can be used in such scenario?'
Thank you.
Mita
A. ILeasable.GetLeasingCharges
If GetLeasingCharges depends only on the data the object already has I could be argued that it may be better choice to make GetLeasingCharges part of ILeasable.
internal interface ILeasable
{
int Id { get; set; }
int GetLeasingCharges();
}
internal class ClubHouse : ILeasable
{
public int Id { get; set; }
public int AreaInSquareFeet { get; set; }
public int GetLeasingCharges() => AreaInSquareFeet * 10;
}
internal class ClubHouse : ILeasable
{
public int Id { get; set; }
public int CarCapcity{ get; set; }
public int GetLeasingCharges() => CarCapcity * 15;
}
B. GetLeasingCharges not part ILeasable
From C#7.0 you can use pattern matching for situations like this.
public static int GetLeasingCharges(ILeasable leasable)
{
// From c#7.0
switch (leasable)
{
case ClubHouse c:
return c.AreaInSquareFeet * 10;
case ShowRoom s:
return s.AreaInSquareFeet * 12;
case Parking p:
throw new ArgumentException(
message: "Parkings cannot be leased!",
paramName: nameof(leasable));
default:
throw new ArgumentException(
message: "Unknown type",
paramName: nameof(leasable));
}
}
Before C#7.0 you could use if.
if (leasable is ClubHouse)
{
var c = (ClubHouse)leasable;
return c.AreaInSquareFeet * 10;
}
else if (leasable is ShowRoom)
{
var c = (ShowRoom)leasable;
return s.AreaInSquareFeet * 12;
}
else if(leasable is Parking)
{
throw new ArgumentException(
message: "Parkings cannot be leased!",
paramName: nameof(leasable));
}
else
{
throw new ArgumentException(
message: "Unknown type",
paramName: nameof(leasable));
}
I quite agree with #tymtam approach. You can also use an abstract class in an alternative.
public abstract class ChargeCalculatingFacadeBase<T> where T : ILeasable
{
LeasableRepository leasableRepository = new LeasableRepository();
public ILeasable leasable;
public void ShowLeasingCharges(int id)
{
leasable = leasableRepository.GetLeasable(id);
var leasingCharge = GetLeasingCharges((T)leasable);
}
public abstract int GetLeasingCharges(T leasable);
}
public class ChargeCalculatingFacade : ChargeCalculatingFacadeBase<ClubHouse>
{
public override int GetLeasingCharges(ClubHouse leasable)
{
var property = leasable;
var areaInSquareFeet = property.AreaInSquareFeet;
return areaInSquareFeet * 10;
}
}
While this might be an overkill, in a case similar to yours I have on a few occasions used a pseudo-DSL approach.
That is, I first come up with a language to express my intent, and then implement it.
What do you need? The ability to express calculations in a readable way. Let's do it this way: assuming you have a class
public class LeaseCalculator
{
public int CalculateLease(int id) ...
I'd like to initialize it like this:
var builder = new LeaseCalculatorBuilder();
LeaseCalculator calculator = builder
.On<ClubHouse>(house => house.AreaInSquareFeet)
.On<Parking>(park => park.CarCapacity)
.On<ShowRoom>(room => room.AreaInSquareFeet)
.Build(leasableRepository);
Is the intent clear? I believe so. If we have a club house, we do the first thing; for parking, something else, etc, etc.
Now, to the implementation. I could also walk step by step, but to cut story short:
public class LeaseCalculatorBuilder
{
internal Dictionary<Type, Func<ILeasable, int>> Calculations { get; } = new Dictionary<Type, Func<ILeasable, int>>();
internal LeaseCalculatorBuilder On<T>(Func<T, int> calculation) where T : class, ILeasable
{
Calculations.Add(typeof(T), (ILeasable c) => calculation((T)c));
return this;
}
internal LeaseCalculator Build(LeasableRepository leasableRepository)
{
return new LeaseCalculator(leasableRepository, this);
}
}
public class LeaseCalculator
{
private readonly Dictionary<Type, Func<ILeasable, int>> _calculations;
private readonly LeasableRepository _leasableRepository;
internal LeaseCalculator(LeasableRepository leasableRepository, LeaseCalculatorBuilder builder)
{
_leasableRepository = leasableRepository;
_calculations = builder.Calculations;
}
public int CalculateLease(int id)
{
ILeasable property = _leasableRepository.GetLeasable(id);
Type type = property.GetType();
if (_calculations.TryGetValue(type, out var calculation))
{
return calculation(property);
}
throw new Exception("Unexpected type, please extend the calculator");
}
}
And finally, a default creator:
public static class DefaultLeaseCalculator
{
internal static LeaseCalculator Build(LeasableRepository leasableRepository)
{
var builder = new LeaseCalculatorBuilder();
LeaseCalculator calculator = builder
.On<ClubHouse>(house => house.AreaInSquareFeet)
.On<Parking>(park => park.CarCapacity)
.On<ShowRoom>(room => room.AreaInSquareFeet)
.Build(leasableRepository);
return calculator;
}
}
Neat?

Is it possible to create generic selector using PropertyInfo?

I'm trying to create a function that will do something with the IEnumerable of any given object for example
public class Sales
{
public float Next { get; set; }
public string ProductId { get; set; }
public float Year { get; set; }
public float Month { get; set; }
public float Units { get; set; }
}
where you can see that it is containing property of floats and string
now what I want is to calculate min max from those float properties
public static IEnumerable<T> GenericSelector<T>(this IEnumerable<T> dataset)
{
foreach (var property in typeof(T).GetProperties())
{
if(property.PropertyType == typeof(float))
{
var min = dataset.Min(x => /*reflection from property variable*/);
var max = dataset.Max(x => /*reflection from property variable*/;
/** more calculation of min max from here **/
}
}
}
is it possible to reflect the property back to selector in this case?
You can use PropertyInfo.GetValue:
foreach (var property in typeof(T).GetProperties())
{
if(property.PropertyType == typeof(float))
{
var min = dataset.Min(x => (float)property.GetValue(x));
var max = dataset.Max(x => (float)property.GetValue(x));
// ...
}
}

Is it possible to grab a static class dynamically using enum?

I want to create configuration for my application using static classes.
Firstly please forgive my ignorance, I'm not a full time c# dev. I come from a Ruby/Javascript world where dynamic access to constants & variables is trivial.
Whether or not this is the right approach here I'm not 100% at the moment. Would be greatful of other suggested approaches.
I have the following static class setup for my config:
public static class Config
{
public static class MaterialQuality
{
public static class Low
{
public const float Value = 0.1f;
public const int Cost = 10;
}
public static class Medium
{
public const float Value = 0.2f;
public const int Cost = 20;
}
public static class High
{
public const float Value = 0.2f;
public const int Cost = 40;
}
}
}
I then have a class Material, which is passed an enum value relating to the aboves types Low,Medium,High.
The reason for the enum in unity this gives a quick way for devs to provide level designers with an option list for a an object.
So by choosing an enum value the level designer can set the properties stored in the config without actually having to enter the values directly onto the object. The values are set against the object when it is initialised.
In the constructor I want to set member variables for Cost & Value from the static config values for the MaterialQuality enum value passed.
public enum MaterialQuality
{
Low,Medium,High
}
public class Material
{
private int Cost;
private float Value;
Material(MaterialQuality quality) {
Cost = Config.MaterialQuality.<quality>.Cost;
Value = Config.MaterialQuality.<quality>.Value;
//in Javascript I'd use associative array access to the object
Cost = Config.MaterialQuality[quality].Cost;
//in Ruby we have const_get() on classes.
Cost = Config.MaterialQuality.const_get(quality).Cost
}
}
The main reason for this approach is to provide single place for configuration & provide a fairly simple way for a non technical person to make changes to parts of the application without having to delve into the main classes. Also it allows me to take advantage of the constants being available in intellisense.
I'm a fan of using dictionaries for this type of configuration.
void Main()
{
var config = Config.Qualities[MaterialQualities.Low];
var cost = config.Cost;
var value = config.Value;
}
public static class Config
{
public static Dictionary<MaterialQualities, MaterialQuality> Qualities =
new Dictionary<MaterialQualities, MaterialQuality>
{
{ MaterialQualities.Low, new MaterialQuality { Value = 0.1F, Cost = 10 }},
{ MaterialQualities.Medium, new MaterialQuality { Value = 0.2F, Cost = 20 }},
{ MaterialQualities.High, new MaterialQuality { Value = 0.2F, Cost = 40 }},
};
}
public class MaterialQuality
{
public float Value { get; set; }
public int Cost { get; set; }
}
public enum MaterialQualities
{
Low, Medium, High
}
Probably better approach would be:
public static class Config
{
public class Material
{
public Material(float value, int cost){
Value = value;
Cost = cost;
}
public float Value {get; private set;}
public int Cost {get; private set;}
public Material GetFor(MaterialQuality quality){
switch(quality){
case MaterialQuality.Low: return new Material(0.1f, 10);
case MaterialQuality.Medium: return new Material(0.2f, 20);
case MaterialQuality.High: return new Material(0.2f, 40);
}
throw new Exception("Unknown material quality " + quality);
}
}
}
and later you can use that:
//....
Material materialData = Material.GetFor(quality);
Cost = materialData.Cost;
Value = materialData.Value;
//...
I would use a struct and static properties in MaterialQuantity instead of an enum. Something like the following:
public struct MaterialQualityInfo
{
public MaterialQualityInfo( float value, int cost )
{
Value = value;
Cost = cost;
}
public float Value { get; private set; }
public int Cost { get; private set; }
}
public static class Config
{
public static class MaterialQuality
{
public static MaterialQualityInfo Low
{
get { return new MaterialQualityInfo( 0.1f, 10 ); }
}
public static MaterialQualityInfo Medium
{
get { return new MaterialQualityInfo( 0.2f, 20 ); }
}
public static MaterialQualityInfo High
{
get { return new MaterialQualityInfo( 0.2f, 40 ); }
}
}
}
public class Material
{
private int Cost;
private float Value;
Material( MaterialQualityInfo quality )
{
Cost = quality.Cost;
Value = quality.Value;
}
}
IMHO, this isn't a good usage of static classes. You should use regular object-oriented programming to solve the issue.
I see that all material qualities have 2 properties in common: Value and Cost. For me, this means that you should design a class called MaterialQuality:
public class MaterialQuality
{
public float Value { get; set; }
public int Cost { get; set; }
}
If material qualities are part of an application configuration, I see that you should design a Configuration class as follows:
public class Configuration
{
public List<MaterialQuality> MaterialQualities { get; } = new List<MaterialQuality>();
}
...and if you want to initialize a configuration per application life-cycle, you can improve Configuration class using static field initializers:
public class Configuration
{
private readonly static Configuration _current = new Configuration();
public static Configuration Current => _current;
public List<MaterialQuality> MaterialQualities { get; } = new List<MaterialQuality>();
}
Now adding new material qualities to current configuration is as easy as the following code:
Configuration.Current.MaterialQualities.Add(new MaterialQualities { Value = 0.1f, Cost = 10 });
If you want to provide a fluent API to add material qualities is also easy: we're going to turn public MaterialQualities properties into an ImmutableList<T> (so you force developers to add materials using the method to do so) and add an AddMaterial method:
public class Configuration
{
private readonly static Configuration _current = new Configuration();
private readonly List<MaterialQuality> _materialQualities = new List<MaterialQuality>();
public static Configuration Current => _current;
public IImmutableList<MaterialQuality> MaterialQualities => _materialQualities.ToImmutableList();
public Configuration AddMaterial(float value, int cost)
{
_materialQualities.Add(new MaterialQuality { Value = value, Cost = cost });
return this;
}
}
...and now adding many materials would look even nicer!
Configuration.Current.AddMaterial(0.1f, 10)
.AddMaterial(0.2f, 20)
.AddMaterial(0.2f, 40);
How about:
public enum MaterialQuality
{
Low, Medium, High
}
public class Material
{
private int Cost;
private float Value;
private readonly Dictionary<MaterialQuality, Tuple<int, float>> storageMap = new Dictionary<MaterialQuality, Tuple<int, float>>
{
{ MaterialQuality.Low, Tuple.Create(10, 0.1f)},
{ MaterialQuality.Low, Tuple.Create(20, 0.2f)},
{ MaterialQuality.Low, Tuple.Create(40, 0.2f)},
};
public Material(MaterialQuality quality)
{
Cost = storageMap[quality].Item1;
Value = storageMap[quality].Item2;
}
}
If you are not using your enum widely, you could do something like:
public class Material
{
public float Value { get; private set; }
public int Cost { get; private set; }
public Material(float value, int cost)
{
Value = value;
Cost = cost;
}
public static Material Low { get { return new Material(0.1f, 10); } }
public static Material Medium { get { return new Material(0.2f, 20); } }
public static Material High { get { return new Material(0.2f, 40); } }
}
And then:
var myLowMaterial = Material.Low;
var myMediumMaterial = Material.Medium;
var myHighMaterial = Material.High;
Unless you are using your enum for something, in which case you could add:
public static Material Get(MaterialQuality quality)
{
switch(quality)
{
case MaterialQuality.Low:
return Low;
case MaterialQuality.Medium:
return Medium;
case MaterialQuality.High:
return High;
}
throw new Exception("We should never go here");
}

DbContext disposed error

I have tried the internet, but could not find a good answer. Here is the code which is having the problem
private void LoadRecords()
{
var data = from record in model.Records
where record.TimeStamp >= oldestRecordVisible
orderby record.TimeStamp descending
select record;
dataGridView1.DataSource = data.ToList();
}
I am using mySql server for the database. And here's the code from the context.cs
using System.Data.Entity;
namespace MilThicknessMonitor3.Models
{
public class DataModel : DbContext
{
public DataModel()
: base("name=DataConnection")
{
}
public DbSet<Record> Records { get; set; }
public DbSet<CaptureSource> CaptureSources { get; set; }
public DbSet<PlcConfiguration> PlcConfigurations { get; set; }
public DbSet<Configuration> Configurations { get; set; }
}
}
Any help will appreciated
Below is the Data Model
using MilThicknessMonitor3.Analytics;
using System;
using System.ComponentModel;
namespace MilThicknessMonitor3.Models
{
public class Record
{
public int Id { get; set; }
[DisplayName("Date/Time")]
public DateTime TimeStamp { get; set; }
[DisplayName("Average Measure (Mils)")]
public double AvgMeasure { get; set; }
[DisplayName("Average Measure (Millimetres)")]
public double AvgMilli { get { return AvgMeasure / 39.37; } }
[DisplayName("Minimum Measure (Mils)")]
public double MinMeasure { get; set; }
[DisplayName("Minimum Measure (Millimetres)")]
public double MinMilli { get { return MinMeasure / 39.37; } }
[DisplayName("Maximum Measure (Mils)")]
public double MaxMeasure { get; set; }
[DisplayName("Maximum Measure (Millimetres)")]
public double MaxMilli { get { return MaxMeasure / 39.37; } }
[DisplayName("Notes")]
public string Notes { get; set; }
#region Testing Fields, Properties, and Methods
private DataLine offset;
internal DataLine Offset
{
get { return offset; }
}
private DataLine baseline;
internal DataLine Baseline
{
get { return baseline; }
}
private float[] results;
public int[] OffsetValues
{
get
{
int[] values = new int[offset.Size];
int index = 0;
foreach (ImageColumn c in offset)
{
values[index] = c.Ys.Count;
index++;
}
return values;
}
}
public int[] BaselineValues
{
get
{
int[] values = new int[baseline.Size];
int index = 0;
foreach (ImageColumn c in baseline)
{
values[index] = c.Ys.Count;
index++;
}
return values;
}
}
public int[] ResultValues
{
get
{
int[] values = new int[results.Length];
for (int i = 0; i < results.Length; i++)
values[i] = (int)Math.Round(results[i]);
return values;
}
}
internal void AddOffset(DataLine offset) { this.offset = offset; }
internal void AddBaseLine(DataLine baseline) { this.baseline = baseline; }
internal void AddResults(float[] results) { this.results = results; }
#endregion
}
}
You need to give some more information on the model object. Where is it created?
Try something like this.
using(var context = new DataModel())
{
//Prepare your Model
var model = RecordsRepository.GetQueryableObject();
//Call LoadRecords
return LoadRecords(model);
}
Well I found the solution for the problem. Basically one of my object was taking up wrong configuration from a table, failing it to initialize and throwing exception and eventually disposing the context.
Thanks everyone for your support.

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