I have a winforms application that is connected to a database which contains a huge amount of measurement data of different datapoints. The data gets updated every few seconds, old values go to an archive table etc. I'm using EF6 for data access.
Now I need to build a GUI that offers some functionality as follows:
The user should be able to define conditions and/or expressions at runtime that then trigger some actions when true. An example in pseudo-code:
if ([Value of Datapoint 203] >= 45 and (TimeStamp of Datapoint 203 < "07:00am")
and (([Value of Datapoint 525] == 1]) or ([Value of Datapoint 22] < 0)])
then set [Value of Datapoint 1234] to ([Value of 203]/4) //or call a method alternatively
or an even simpler example in natural language (differs from the above):
if it is cold and raining, turn on machine XY
where cold and raining are values of certain datapoints and turn on machine is a method with a given parameter XY.
These expressions need to be saved and then evaluated in regular intervals of some minutes or hours. I did not face such a requirement before and I hardly know where to start. What would be the best practice? Is there maybe some sample code you know of? Or are there even controls or libraries for this?
Update: Breaking it down to something more specific:
Suppose I have a class like this:
class Datapoint
{
public int Id { get; set; }
public DateTime TimeStamp { get; set; }
public int Value { get; set; }
}
During runtime I have two objects of this type, DatapointA and DatapointB. I want to enter the following into a textbox and then click a button:
DatapointA.Value>5 && ( DatapointB.Value==2 || DatapointB.Value==7 )
Depending on the actual values of these objects, I want to evaluate this expression string and get a true or false. Is this possible?
Related
thanks in advance for your help. I'm a hobbyist playing around with building an incremental clicker to learn various coding techniques and am trying to find a way to streamline a portion of my script. I'm going to have 80-100 different clickable images and I'd like the image to change color/turn on and off when it can/it can't be clicked to show a user when it can be interacted with. The conditions for when each can be clicked are different for every image. So far I've tried SetActive() and setting fillAmount to 0 or 1 however it's resulting in long and mostly repetitive code. Below is how I've tried both ways, could anyone recommend a way to streamline this so I don't have to write 4 lines of code for every clickable object? I've tried writing a quick program however I keep getting stuck with the conditions being different for every image.
if ((data.food >= data.hutClickFoodConsumption) && (data.energy >= data.hutClickEnergyConsumption))
hutClickYes.SetActive(true);
else
hutClickYes.SetActive(false);
if ((data.food >= data.townPlannersClickFoodConsumption) && (data.energy >= data.townPlannersClickEnergyConsumption))
townPlannersClickYes.fillAmount = 1;
else
townPlannersClickYes.fillAmount = 0;
if ((data.food >= data.hiRiseClickFoodConsumption) && (data.energy >= data.hiRiseClickEnergyConsumption))
hiRiseClickYes.fillAmount = 1;
else
hiRiseClickYes.fillAmount = 0;
With such a large number of items, I generally like to store as much information as sensible within each item. And then I'll store those items in a collection. Because of the lack of Dictionary<K, V> serialisation in Unity, it's usually a List<T> so we can use the Inspector.
An example of that for your case might look something like this:
[Serializable]
public class ItemData
{
public string Name;
public float FoodConsumption;
public float EnerguConsumption;
public GameObject ItemObject; // (see notes)
// add any extra item data here ...
}
public class Test : MonoBehaviour
{
[SerializeField] private List<ItemData> _allItems;
// Include your 'data' field or property here as well.
public void Setup ( )
{
foreach ( var i in _allItems )
i.ItemObject.SetActive (
( data.food >= i.FoodConsumption ) &&
( data.energy >= i.EnerguConsumption ) );
}
}
With this approach, you can reduce the amount of code from hundreds of lines, to half a dozen. Also, the type of the referenced object could be a GameObject (as shown), or an Image if you're using the uGUI (think Canvas), or another referenced object to suit your needs.
The result of the above code then looks like this:
Obviously, this only works if all of the conditions can be boiled down to the boolean check in the example. But, it IS possible to add further data to extend the type checking. A quick example would be adding boolean values to the item data, indicating what fields need to be checked, and/or whether a value need to be less then, equal or greater than.
We are writing a data conversion application.
We have 10s of 1000s of equations that need to be extracted into a template aka ‘model’.
The model will take the most common unit of measure for a given set of equations.
Then each equation's value must be adjusted to ensure that its value corresponds to the unit of measure on the model.
So, I am looking to use UnitsNet to convert values of variables, given a source variable and its unit, to a target unit.
The issue I have is that we don’t know at compile time either what the source unit is, nor the target unit.
All we have is the source and target unit string abbreviations in the equation which comes in at runtime (and some of these will be custom units).
Simple example:
Target Unit: mA (Miliamperes)
Source Equation: Is=8A (Amperes)
We need to be able to recognize the unit of measure from the abbreviation, compare it to a target unit and then adjust the value accordingly :
e.g. in the above case we would multiply 8 Amperes by 1000 to equal 8000 Miliamperes.
I cannot see a succinct way to do this with UnitsNet.
Something crude like this is all I have so far (this is a unit test written in xUnit):
[Theory]
[InlineData("A", "mA", "8")]
public void DoConversion(string sourceUnit, string targetUnit, string variableValue)
{
double result = 0;
ElectricCurrent sourceCurrent;
if (ElectricCurrent.TryParse($"{variableValue}{sourceUnit}", out sourceCurrent))
{
ElectricCurrent targetCurrent;
if (ElectricCurrent.TryParse($"1{targetUnit}", out targetCurrent))
{
var electricCurrentUnit = GetElectricCurrentUnitFromAbbreviation(targetUnit);
if (electricCurrentUnit == ElectricCurrentUnit.Ampere)
{
result = sourceCurrent.Amperes;
}
if (electricCurrentUnit == ElectricCurrentUnit.Milliampere)
{
result = sourceCurrent.Milliamperes;
}
}
}
result.Should().Be(8000);
// TODO: Add every other combination of all possible Units and their Scales- OMG!!!
}
private ElectricCurrentUnit GetElectricCurrentUnitFromAbbreviation(string abbreviation)
{
// Is there a better way to determine WHICH ElectricCurrentUnit the target is?
if (abbreviation == "A")
return ElectricCurrentUnit.Ampere;
if (abbreviation == "mA")
return ElectricCurrentUnit.Milliampere;
return ElectricCurrentUnit.Undefined;
}
But the list of possible units we have to cater for is large, so I don’t want to have to write it this way.
It seems like there’s got to be a better way.
Would really appreciation your expert insight into this.
This was answered on github: https://github.com/angularsen/UnitsNet/issues/220
Proposed solution
This gives you some tools to more easily work with dynamic conversions, using string representations of quantities and units.
New class UnitConverter
New property Units on quantities, ex: LengthUnit[] Units { get; } on Length
Renamed (obsoleted) UnitClass enum to QuantityType for new naming convention
This allows the following scenario:
// Get quantities for populating quantity UI selector
QuantityType[] quantityTypes = Enum.GetValues(typeof(QuantityType)).Cast<QuantityType>().ToArray();
// If Length is selected, get length units for populating from/to UI selectors
LengthUnit[] lengthUnits = Length.Units;
// Perform conversion by using .ToString() on selected units
double centimeters = UnitConverter.ConvertByName(5, "Length", "Meter", "Centimeter");
double centimeters2 = UnitConverter.ConvertByAbbreviation(5, "Length", "m", "cm");
I'm writing code in a C# library to do clustering on a (two-dimensional) dataset - essentially breaking the data up into groups or clusters. To be useful, the library needs to take in "generic" or "custom" data, cluster it, and return the clustered data.
To do this, I need to assume that each datum in the dataset being passed in has a 2D vector associated with it (in my case Lat, Lng - I'm working with co-ordinates).
My first thought was to use generic types, and pass in two lists, one list of the generic data (i.e. List<T>) and another of the same length specifying the 2D vectors (i.e. List<Coordinate>, where Coordinate is my class for specifying a lat, lng pair), where the lists correspond to each other by index. But this is quite tedious because it means that in the algorithm I have to keep track of these indices somehow.
My next thought was to use inferfaces, where I define an interface
public interface IPoint
{
double Lat { get; set; }
double Lng { get; set; }
}
and ensure that the data that I pass in implements this interface (i.e. I can assume that each datum passed in has a Lat and a Lng).
But this isn't really working out for me either. I'm using my C# library to cluster stops in a transit network (in a different project). The class is called Stop, and this class is also from an external library, so I can't implement the interface for that class.
What I did then was inherit from Stop, creating a class called ClusterableStopwhich looks like this:
public class ClusterableStop : GTFS.Entities.Stop, IPoint
{
public ClusterableStop(Stop stop)
{
Id = stop.Id;
Code = stop.Code;
Name = stop.Name;
Description = stop.Description;
Latitude = stop.Latitude;
Longitude = stop.Longitude;
Zone = stop.Zone;
Url = stop.Url;
LocationType = stop.LocationType;
ParentStation = stop.ParentStation;
Timezone = stop.Timezone;
WheelchairBoarding = stop.WheelchairBoarding;
}
public double Lat
{
get
{
return this.Latitude;
}
}
public double Lng
{
get
{
return this.Longitude;
}
}
}
which as you can see implements the IPoint interface. Now I use the constructor for ClusterableStop to first convert all Stops in the dataset to ClusterableStops, then run the algorithm and get the result as ClusterableStops.
This isn't really what I want, because I want to do things to the Stops based on what cluster they fall in. I can't do that because I've actually instantiated new stops, namely ClusterableStops !!
I can still acheive what I want to, because e.g. I can retrieve the original objects by Id. But surely there is a much more elegant way to accomplish all of this? Is this the right way to be using interfaces? It seemed like such a simple idea - passing in and getting back custom data - but turned out to be so complicated.
Since all you need is to associate a (latitude, longitude) pair to each element of 2D array, you could make a method that takes a delegate, which produces an associated position for each datum, like this:
ClusterList Cluster<T>(IList<T> data, Func<int,Coordinate> getCoordinate) {
for (int i = 0 ; i != data.Count ; i++) {
T item = data[i];
Coordinate coord = getCoord(i);
...
}
}
It is now up to the caller to decide how Coordinate is paired with each element of data.
Note that the association by list position is not the only option available to you. Another option is to pass a delegate that takes the item, and returns its coordinate:
ClusterList Cluster<T>(IEnumerable<T> data, Func<T,Coordinate> getCoordinate) {
foreach (var item in data) {
Coordinate coord = getCoord(item);
...
}
}
Although this approach is better than the index-based one, in cases when the coordinates are not available on the object itself, it requires the caller to keep some sort of an associative container on T, which must either play well with hash-based containers, or be an IComparable<T>. The first approach places no restrictions on T.
In your case, the second approach is preferable:
var clustered = Cluster(
myListOfStops
, stop => new Coordinate(stop.Latitude, stop.Longitude)
);
Have you considered using Tuples to do the work - sometimes this is a useful way of associating two classes without creating a whole new class. You can create a list of tuples:
List<Tuple<Point, Stop>>
where Point is the thing you cluster on.
i have a situation, i need to process an jagged array of 20k registers every time a user press a key. I have a grid and while the user is typing the system shows a filtered result in a grid. so. So i have a jagged array filled with all 20k registers. and the i have a list (global to the control) and it´s cleaned up every time the user press a key and filled up with just the filtered registers and then show then in the grid.
Here is the code
the model
public struct PlayerLookUpAdapter
{
[Browsable(false)]
public decimal Id { get; set; }
[DisplayName("Número")]
public String Number { get; set; }
[DisplayName("Nombre")]
public String Name { get; set; }
[DisplayName("Apellido")]
public String Surname { get; set; }
[DisplayName("DNI")]
public String Document { get; set; }
[DisplayName("Estado")]
public String Status { get; set; }
}
private PlayerLookUpAdapter[] _source; // here are the 20k registers
List<PlayerLookUpAdapter> filteredOut = new List<PlayerLookUpAdapter>(); // here the filtered ones
// this code is executed every time the user press a key
private void tb_nro_KeyUp(object sender, KeyEventArgs e)
{
if (!(e.KeyCode.Equals(Keys.Enter) || e.KeyCode.Equals(Keys.Down)) && _source!=null)
{
String text = tb_nro.Text.ToUpper();
if (String.IsNullOrEmpty(text))
{
fg.DataSource = _source;
fg.Refresh();
return;
}
fg.DataSource = null;
filteredOut.Clear();
int length = _source.Length;
for (int i = 0; i < length; i++)
{
PlayerLookUpAdapter cur = _source[i];
if (cur.Number.ToUpper().StartsWith(text) || cur.Surname.ToUpper().StartsWith(text) || cur.Name.ToUpper().StartsWith(text))
filteredOut.Add(cur);
}
fg.DataSource = filteredOut;
SetGridColumnsProperties();
fg.Refresh();
}
else
{
fg.Focus();
}
}
is it a good solution in terms of memory usage and performance? have you got any advice? How can i gain more speed. It works realy good, but what about if i got 100k registers instead of 20k?
Thanks in advance.
I think this should be a prime example for using a tree.
If you lay your Data down in a Tree (i actually don't know if C#/.Net supports a Tree Data-Structure, or you have get your own hands dirty).
The Speed you search in a Tree will increase in comparison for searching in an Array (because a Tree gots a search-speed of somehting like O(n)=n*log(n))
The Theory is easy: if a User Types in a Literal, the Tree goes to the Node starting with this Literal, on this nodes are all possible other nodes and so on. For example: The User types in an "t" you go to the "t" Node, then he types in an "e" you go to the subnode "te", there are some other subnodes like "test" and the system will propose the User these subnodes.
firts of all you could improve a bit your code: the StartWith method has an overload who takes the string comparison as well. you could set it as "OrdinalIgnoreCase" to avoid to upper all the strings but I don't think you will gain a lot.
The only way you have to speed up you search is go for a Search engine as Lucene.net.
http://www.codeproject.com/KB/library/IntroducingLucene.aspx
You want a prefix tree for this.
Here is one implementation:
A Reusable Prefix Tree using Generics in C# 2.0
You could probably use the StringComparison.OrdinalIgnoreCase option on your string comparisons and avoid having to call ToUpper on all your strings 20k times.
Ideally, first you need to decide how slow is too slow based on your best estimates for typical usage of your program. After all premature optimisation is the root of all evil.
Precalculate the ToUpper() call so you dont have to do it every time. You could maintain a second list where all the strings are stored uppercase.
Secondly you should search the filtered list (instead of the whole list) in case a key is added to the search string. The new (longer) string can never be outside of the filtered results.
I'm trying to figure out how to design a small application more elegantly, and make it more resistant to change.
Basically it is a sort of project price calculator, and the problem is that there are many parameters that can affect the pricing. I'm trying to avoid cluttering the code with a lot of if-clauses for each parameter, but still I have e.g. if-clauses in two places checking for the value of the size parameter.
I have the Head First Design Patterns book, and have tried to find ideas there, but the closest I got was the decorator pattern, which has an example where starbuzz coffee sets prices depending first on condiments added, and then later in an exercise by adding a size parameter (Tall, Grande, Venti). But that didn't seem to help, because adding that parameter still seemed to add if-clause complexity in a lot of places (and this being an exercise they didn't explain that further).
What I am trying to avoid is having to change several classes if a parameter were to change or a new parameter added, or at least change in as few places as possible (there's some fancy design principle word for this that I don't rememeber :-)).
Here below is the code. Basically it calculates the price for a project that has the tasks "Writing" and "Analysis" with a size parameter and different pricing models. There will be other parameters coming in later too, like "How new is the product?" (New, 1-5 years old, 6-10 years old), etc. Any advice on the best design would be greatly appreciated, whether a "design pattern" or just good object oriented principles that would make it resistant to change (e.g. adding another size, or changing one of the size values, and only have to change in one place rather than in several if-clauses):
public class Project
{
private readonly int _numberOfProducts;
protected Size _size;
public Task Analysis { get; set; }
public Task Writing { get; set; }
public Project(int numberOfProducts)
{
_numberOfProducts = numberOfProducts;
_size = GetSize();
Analysis = new AnalysisTask(numberOfProducts, _size);
Writing = new WritingTask(numberOfProducts, _size);
}
private Size GetSize()
{
if (_numberOfProducts <= 2)
return Size.small;
if (_numberOfProducts <= 8)
return Size.medium;
return Size.large;
}
public double GetPrice()
{
return Analysis.GetPrice() + Writing.GetPrice();
}
}
public abstract class Task
{
protected readonly int _numberOfProducts;
protected Size _size;
protected double _pricePerHour;
protected Dictionary<Size, int> _hours;
public abstract int TotalHours { get; }
public double Price { get; set; }
protected Task(int numberOfProducts, Size size)
{
_numberOfProducts = numberOfProducts;
_size = size;
}
public double GetPrice()
{
return _pricePerHour * TotalHours;
}
}
public class AnalysisTask : Task
{
public AnalysisTask(int numberOfProducts, Size size)
: base(numberOfProducts, size)
{
_pricePerHour = 850;
_hours = new Dictionary<Size, int>() { { Size.small, 56 }, { Size.medium, 104 }, { Size.large, 200 } };
}
public override int TotalHours
{
get { return _hours[_size]; }
}
}
public class WritingTask : Task
{
public WritingTask(int numberOfProducts, Size size)
: base(numberOfProducts, size)
{
_pricePerHour = 650;
_hours = new Dictionary<Size, int>() { { Size.small, 125 }, { Size.medium, 100 }, { Size.large, 60 } };
}
public override int TotalHours
{
get
{
if (_size == Size.small)
return _hours[_size] * _numberOfProducts;
if (_size == Size.medium)
return (_hours[Size.small] * 2) + (_hours[Size.medium] * (_numberOfProducts - 2));
return (_hours[Size.small] * 2) + (_hours[Size.medium] * (8 - 2)) + (_hours[Size.large] * (_numberOfProducts - 8));
}
}
}
public enum Size
{
small, medium, large
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
List<int> quantities = new List<int>();
for (int i = 0; i < 100; i++)
{
quantities.Add(i);
}
comboBoxNumberOfProducts.DataSource = quantities;
}
private void comboBoxNumberOfProducts_SelectedIndexChanged(object sender, EventArgs e)
{
Project project = new Project((int)comboBoxNumberOfProducts.SelectedItem);
labelPrice.Text = project.GetPrice().ToString();
labelWriterHours.Text = project.Writing.TotalHours.ToString();
labelAnalysisHours.Text = project.Analysis.TotalHours.ToString();
}
}
At the end is a simple current calling code in the change event for a combobox that set size... (BTW, I don't like the fact that I have to use several dots to get to the TotalHours at the end here either, as far as I can recall, that violates the "principle of least knowledge" or "the law of demeter", so input on that would be appreciated too, but it's not the main point of the question)
Regards,
Anders
First of all, you should in my opinion rethink you design. Projects don't look like that and as far as I looked in your code, you have no way to add more tasks to a project. Also consider separating the Project and the way in whch you will calculate the prize. What if you have different calculation methods? It is also about responsibility, soon you project might grow and it will be hard to separate the way you calculate the price and the project structure. Generally avoiding "if" is done using polymorphism - maybe you sould like to have different project types depending on their parameters. This can be achieved using the Factory Method, which will take the arguments, do the "if"s once and than create some Project subtype, which will know how to calculate its prize correctly. If you separate the project and the calculation, than consider instead using strategy pattern for calculating the prize. The concern about law of demeter is here adequate, because you expose the tasks. Try instead using a method which will return the total price and will delegate. The reason is, that class where will that method be (project or the calculating strategy) could decide how to calculate it, it could take also information from other tasks. You would have to adjust the method if you plan to add more tasks, maybe use one method with string or enum parameter to select a concrete task to calculate prize. BTW. why do you use underscores so much?
If you have such kind of if...else statement based on the properties of class, try to refacor it using strategy pattern. You can try the book called "Refactor to Patterns", which is a good book on refatoring.
He is using underscores for member varibles. you could use "me." or "this." instead, but its just as clear. I believe this comes from some old java style standard? personally I quite like it.
So the application that you have designed has what I would say is one major gap in the design principal:
It assumes a single usage dataset.
By this I mean that it assumes, there are only two possible tasks, each has a hard coded price (something that in the business world simply doesn't exist), and each task calculates is "hours" deterministically against against a constant set of sizes. My advise is to make almost all of this configurable either by use of a database to store new possible tasks/properties/prices/hourly ratios/sizes or by some other storage means and write a configuration form for managing it.
This will almost immediately remove the design problem you are implying by the fact that you remove all hard coded domain contexts and instead set a configuration precedent that can then be exposed via API if someone doesn't like your configuration method or wants to use this in some other way.
Edit: I wanted to comment this below but ran out of room:
extend the depth of your xml to meaningfully represent the larger datastructures (WritingTask and AnalysisTask) as well as their component parts (properties and methods). The methods can often be defined by a set of rules. You can tokenize properties and rules so they can be interacted with independently. Example:
<task name="WritingTask">
<property name="numberofproducts" type="int"/>
<property name="Size" type="size">
<property name="Price" type="decimal">
<param name="priceperhour" value="650">
</property>
<property name="hours" type="Dictionary">
<param name="Size.small" value="125"/>
<param name="Size.medium" value="100"/>
<param name="Size.large" value="60"/>
</property>
<method name="TotalHours">
<rule condition="_size == Size.Small">
<return value="_hours[_size] * _numberofproducts"/>
</rule>
<rule condition="_size == Size.medium">
<return value="(_hours[Size.small] * 2) + (_hours[Size.medium] * _numberOfProducts - 2))"/>
</rule>
<return value="(_hours[Size.small] * 2) + (_hours[Size.medium] * (8 - 2)) + (_hours[Size.large] * (_numberOfProducts - 8))"/>
</method>
</task>
Anyway it is entirely too late in the morning for me to try this any further but I will follow up tomorrow with you. By setting resultant properties and associating methods in configuration with rules, you leave the reconciliation of the if's to your dataset (it should know best) and tune your code to interpret this data accurately. It stays flexible enough to handle growth (through a sudo language for dataset creation) but remains unchanged internally without great need to improve a more universal operation.