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);
}
}
}
I have a problem. I have a few hexagons drawn in SkiaSharp. All the corners are stored in a List<HexagonRegistryList>.
Now I want to know how many shared edges the a hexagon has with the rest of the hexagons, so I created this code:
public class HexagonRegistryList
{
public int HexagonNum { get; set; }
public float x1 { get; set; }
public float y1 { get; set; }
public float x2 { get; set; }
public float y2 { get; set; }
public float x3 { get; set; }
public float y3 { get; set; }
public float x4 { get; set; }
public float y4 { get; set; }
public float x5 { get; set; }
public float y5 { get; set; }
public float x6 { get; set; }
public float y6 { get; set; }
public int ShapeNum { get; set; }
public HexagonRegistryList()
{
this.AdjacentShapeNumbers = new List<int>();
}
public List<int> AdjacentShapeNumbers { get; set; }
public IEnumerable<(float x, float y)> GetPoints()
{
yield return (x1, y1);
yield return (x2, y2);
yield return (x3, y3);
yield return (x4, y4);
yield return (x5, y5);
yield return (x6, y6);
}
public bool IsAdjacentTo(HexagonRegistryList other)
{
var isAdjacentTo = GetPoints().Intersect(other.GetPoints()).Count() >= 2;
if (isAdjacentTo)
{
if (other.ShapeNum != 0)
{
AdjacentShapeNumbers.Add(other.ShapeNum);
}
}
return isAdjacentTo;
}
}
Now this code works, except for points that are not exactly the same but have a difference of 0.001 pixel. So I want to change this to a comparison function which checks if the point of the other corner is closer then 1 pixel away, because that should also be allowed. Can someone help me with this.
I already tried this code, but that just ignores it and still returns false:
public struct PointComparer : IEqualityComparer<(float x, float y)>
{
public bool Equals((float x, float y) p1, (float x, float y) p2)
{
return Math.Abs(p1.x - p2.x) < 1f && Math.Abs(p1.y - p2.y) < 1f;
}
public int GetHashCode((float x, float y) obj)
{
return obj.GetHashCode();
}
}
then I changed this line:
var isAdjacentTo = GetPoints().Intersect(other.GetPoints()).Count() >= 2;
to:
var isAdjacentTo = GetPoints().Intersect(other.GetPoints(), new PointComparer()).Count() >= 2;
But like I already told u, that doesn't work...
Can someone tell me how to make this work?
Since the hexagons all have the same rotation degree and same size you can simply the problem quite a lot.
The main idea is to calculate the distance between two hexagons' center. If the distance between their center point is 2x radius ± 1pixel (or whatever epsilon you wish) then they "might" share one edge.
Now take the vector between the two center point and calculate the angle of the vector. If (angle - 30) % 60 == 0 then they share one edge.
Special case: if two hexagons completely overlap then they will have the same center point
This way you only have to do two comparison with every other hexagons instead of 6x6 comparisons if you do the edge compare way.
Implementation should be quite trivial. The only tricky part would be to apply math formula to find the hexagon's center point. So I will leave it as exercise.
Edit:
Since its a hexagon grid, you got multiple ways of solving this. The center point way still applies. As long as the difference between the center points is less than 2x radius + 1pixel they share one edge. Or you can calculate the distance between two line segments. If the distance between any edge a in hexagon A and any edge b in hexagon B is less than the radius then those two hexagon shares an edge.
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));
// ...
}
}
I want to create a Dictionary<Coordinate, Status>, but the key is always equals to "Bot.Core.Games.Coordinate".
Classes
Coordinate
public class Coordinate
{
public int x { get; set; }
public int y { get; set; }
}
Status
public class Enums
{
public enum Status { UNCAPTURED, PLAYER1, PLAYER2, WIN }
}
First try
Dictionary<Coordinate, Status> Fields { get; set; } = new Dictionary<Coordinate, Status>()
{
{new Coordinate() { x = 0, y = 0 }, Status.UNCAPTURED}
}
Second try
I did some research and I found this: Use custom object as Dictionary Key
So the code now looks like this:
public class Coordinate
{
public int x { get; set; }
public int y { get; set; }
public bool Equals(Coordinate coordinate) => coordinate.x.Equals(x) && coordinate.y.Equals(y);
public bool Equals(object o) => Equals(o as Coordinate);
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode();
}
Third try
Since none of the previously tried code works I did more research and found this.So now the code is:
public class Coordinate
{
public int x { get; set; }
public int y { get; set; }
public class CoordinateEqualityComparer : IEqualityComparer<Coordinate>
{
public bool Equals(Coordinate a, Coordinate b) => ((a.x == b.x) & (a.y == b.y));
public int GetHashCode(Coordinate obj)
{
string combined = obj.x + "|" + obj.y;
return (combined.GetHashCode());
}
}
}
Dictionary<Coordinate, Status> Fields { get; set; } = new Dictionary<Coordinate, Status>(new Coordinate.CoordinateEqualityComparer())
{
{new Coordinate() { x = 0, y = 0 }, Status.UNCAPTURED}
}
The key is always "Bot.Core.Games.Coordinate". How to fix this?
You are missing an override in your second try:
public override bool Equals(object o)
The key is always displayed as Bot.Core.Games.Coordinate because in default, the ToString method returns the class name and this is the method the debugger calls to display its value. If you override the method like this:
public override string ToString() => $"{x} / {y}";
It will display its true value.
The problem with your third try was (as was pointed out by Camilo Terevinto and ZorgoZ) your equality comparison - try
public override bool Equals(Coordinate a, Coordinate b)
{
return ((a.x == b.x) && (a.y == b.y));
}
instead
I have written the code below, but i see that for to access the width and the length for the last child which is badRectangle is by overriding everything inhrerited from the Rectangle and shape class, which means i have to duplicate the input and i i had 6 or more levels of inheritance the code would kind of confuse and repeat a lot of things.
This code works correctly but is the correct way of dealing with inheritance in C#.
class Program
{
static void Main(string[] args)
{
badRectangle myRect = new badRectangle(true,"Rectangle",23.0,23);
Console.WriteLine("The Area of your Rectangle = " + myRect.getArea().ToString()
+ "\nAnd " + myRect.getStatus());
Console.ReadLine();
}
public abstract class shape
{
string type;
public abstract double getArea();
public shape(string type)
{
this.type = type;
}
}
public class rectangle : shape
{
double width, length;
public rectangle(string type, double width, double length):base(type)
{
this.width = width;
this.length = length;
}
public override double getArea()
{
return width * length;
}
}
public class badRectangle : rectangle
{
double width, length;
bool badOrNot = false;
public badRectangle(bool badOrNot,string type, double width, double length):base(type,width,length)
{
this.badOrNot = badOrNot;
this.width = width;
this.length = length;
}
public string getStatus()
{
string answer = "No, Rectangle is not bad";
if (badOrNot == true)
{
answer = "Yes, Rectangle is bad";
}
return answer;
}
public override double getArea()
{
return width * length;
}
}
}
This would be the "correct" or conventional way to do this in C#:
public abstract class Shape
{
public string Type { get; private set; }
public abstract double Area { get; }
public Shape(string type)
{
this.Type = type;
}
}
public class Rectangle : Shape
{
public double Length { get; private set; }
public double Width { get; private set; }
public Rectangle(string type, double width, double length)
: base(type)
{
this.Width = width;
this.Length = length;
}
public override double Area { get { return this.Width * this.Length; } }
}
public class BadRectangle : Rectangle
{
public bool BadOrNot { get; private set; } = false;
public BadRectangle(string type, double width, double length, bool badOrNot)
: base(type, width, length)
{
this.BadOrNot = badOrNot;
}
public string Status
{
get
{
string answer = "No, Rectangle is not bad";
if (this.BadOrNot == true)
{
answer = "Yes, Rectangle is bad";
}
return answer;
}
}
}
You don't need to set width and length in the derived classes again, just pass them to the constructor of the base class. If you need to access them in the derived class, make them protected. The getArea() doesn't have to be overridden if it does the same thing.