Using an enum value to represent two enum values - c#

Picture the scene.
public enum SaveStates
{
Saved, //Represents a successful save.
SavedWithChanges, //Represents a successful save, where records were modified
SavedWithoutChanges //Represents a successful save, but no records were modified
}
In this scenario, the enumeration can be considered Saved if it's SavedWithChanges or SavedWithoutChanges.
So if I were to have a variable like this:
SaveStates lastState = SaveStates.SavedWithoutChanges;
I'd ideally like to do something like this:
if (lastState == SaveStates.Saved)
{
//The state is saved, do something awesome.
}
I can of course do this:
if (lastState == SaveStates.SavedWithChanges || lastState == SaveStates.SavedWithoutChanges)
{
...
However this is a bit tedious and I can't assume that another developer is going to understand how to correctly use the enumeration.
Each enumeration is required as there may be an instance where we might want to do something specific in the event of a save where there has been no changes for example.
I'm open to alternative design ideas.

If what worries you is code readability, you can use a little extension method like this:
public static class SaveStatesExtension
{
public static bool IsSavedState(this SaveStates state) {
return state == SaveStates.SavedWithChanges ||
state == SaveStates.SavedWithoutChanges;
}
}
Then your usage example becomes:
if (lastState.IsSavedState())
{
//The state is saved, do something awesome.
}
Of course the Saved member in the enum is no longer needed in this case.

If you're going to do it with a Flags enum, you should make it self-documenting
[Flags]
public enum SaveStates
{
Saved = 1,
WithChanges = 2,
SavedWithoutChanges = Saved, // a bit pointless! Its the same as Saved
SavedWithChanges = Saved | WithChanges // has value "3"
}
And then, as per other answers
if ((lastState & SaveStates.Saved) == SaveStates.Saved)
{
}

You can achieve this as follows, going by the example of the link I've posted under the question but using non-exclusive flag values. Note that both SavedWithChanges and SavedWithoutChanges contain the bit 1, assigned to Saved.
[Flags]
public enum SaveStates
{
Saved = 1,
SavedWithChanges = 3,
SavedWithoutChanges = 5
}
if ((lastState & SaveStates.Saved) == SaveStates.Saved)
{
}
However, this can be rather unintuitive to other developers - usually flag enums are not used this way. So explicitly stating all conditions with all enum values might be much more readable. Very good idea posted by Konamiman:
public static bool IsSaved(SaveStates state)
{
return state == SaveStates.SavedWithChanges
|| state == SaveStates.SavedWithoutChanges;
}
combines best of two worlds: principle of least astonishment satisfied while being concise and readable.

What about changing your enumeration?
public enum SaveStates
{
NotSaved, //Represents "not saved" state
SavedWithChanges, //Represents a successful save, where records were modified
SavedWithoutChanges //Represents a successful save, but no records were modified
}
In this case you can use negation for the purpose you're speaking of:
if (lastState != SaveStates.NotSaved)
{
//The state is saved, do something awesome.
}
Also, it gives you an enumeration value which can be used as the "default" one which is considered a good, "clean code" practice.

I would prefer this:
SaveStates[] savedWithOrWithoutChanges = { SaveStates.SavedWithChanges, SaveStates.SavedWithoutChanges };
if (savedWithOrWithoutChanges.Contains(lastStat))
{
...
}
This is very intuitive, every developer will understand it.

Instead of one enum to represent two things why not just use two bool values. One to indicate if it is saved and the other to indicate if it is "with changes". Then you'd just ignore the second if the first is false.
private bool saved;
private bool withChanges;
public void SomeMethod()
{
if (saved)
{
Console.WriteLine("Saved");
if (withChanges)
{
Console.WriteLine("With Changes");
}
else
{
Console.WriteLine("Without Changes");
}
}
else
{
Console.WriteLine("Not saved");
}
}

Related

How do I use a boolean on my model that wraps a string value from the database?

Weird question, and there may not be an answer... I inherited an old mysql database where unfortunately many of the "boolean" fields were set up as VARCHAR instead of the more appropriate TINYINT(1)...
I'm now running Entity Framework Core on top of the database. Since I don't know everywhere the boolean values are used, I can't update the database quite yet, but I would like to be able to actually work with the string values as booleans in EF... Is there a way to change the model types so the model wraps up everything neatly as bool but it still treats the fields as strings when I push it to the database?
Essentially, in my code, I want to be able to do this:
object.IsGood = true;
Instead of this: object.IsGood = "TRUE"
And my model would just discreetly handle the value conversion, something like this for writing to the database (and I'd need another converter for reading the boolean values back from the database):
string databaseValue = "";
if (object.IsGood)
{
databaseValue = "TRUE";
}
else
{
databaseValue = "FALSE";
}
Any way I can see of doing it, I'd be actually changing the database when I change the model... I know I could wrap the model itself into another class, but that seems confusing. I'd love to just update the database, but that could be a huge pain to unravel all the possible places that code touches these values... so I was hoping there was an intermediate solution.
I always search for this type of thing under the terms "mapping" or "wrapper" and those were not bringing up anything from the documentation that seemed useful... Christopher's comment got me on the right track and I got what I was searching for.
Apparently "Value Conversions" are what I was looking for:
Value Conversions EF Core
Edit: I've removed the docs example since anyone can look that up. I'm adding my real example below.
Since I wanted to convert back and forth between a string and a boolean, I created this converter as a static value so I could reuse it in a couple of models:
public static class EntityFrameworkCoreValueConverters
{
/// <summary>
/// converts values stored in the database as VARCHAR to a nullable bool
/// handles "TRUE", "FALSE", or DBNULL
/// </summary>
public static ValueConverter<bool?, string> dbVarCharNullableToBoolNullableConverter = new ValueConverter<bool?, string>(
v => v == true ? "TRUE" : v == false ? "FALSE" : null,
v => v.ToUpper() == "TRUE" ? true : false
);
}
Note that there already exists a BoolToStringConverter as part of the Microsoft.EntityFrameworkCore.Storage.ValueConversion namespace, but this doesn't appear to handle null values, which I needed.
Then I can change my model values to bool? instead of string, but leave alone the actual database value types.
The dbVarCharNullableToBoolNullableConverter can then be applied in my OnModelCreating method (or in my case Configure on the model itself which gets applied in the OnModelCreating method:
public void Configure(EntityTypeBuilder<MachineHelpRequests> builder)
{
//... model builder code above
builder.Property(e => e.IsAcknowledged)
.HasColumnName("acknowledged_mhr")
.HasColumnType("varchar(45)")
.HasConversion(EntityFrameworkCoreValueConverters.dbVarCharNullableToBoolNullableConverter);
//... model builder code below
}
This is probably not the best solution but it might get you by until you can refactor the DB.
Add a partial class to the Model and implement the appropriate getters and setters.
partial class Model
{
[NotMapped]
public bool FieldABool
{
get
{
return FieldA == "TRUE";
}
set
{
if (value == true)
{
FieldA = "TRUE";
}
else
{
FieldA = "FALSE";
}
}
}
}

C# replacing huge if-else statement

let's say i have Item object witch mostly holds enum properties like this
public enum Shape
{
square = 1,
trangle = 2,
any = 3
}
public enum Color
{
blue = 1,
red = 2,
yellow = 3,
green = 4
}
public enum Material
{
glass = 1,
wood = 2,
metal = 3
}
public class Item
{
public Shape ItemShape { get; set; }
public Color ItemColor { get; set; }
public Material ItemMaterial { get; set; }
}
What am trying to do is depends of combination of whole three properties i need to do some action later;
I was thinking to use if-else combination like:
if(item.ItemShape == Shape.square && item.ItemColor == Color.blue && item.ItemMaterial == Material.glass)
{
//call Action1
}
else if(item.ItemShape == Shape.square && item.ItemColor == Color.blue && item.ItemMaterial == Material.wood)
{
// action2
}
......
Problem is that i have around 16 of combinations, so it will be huge if-else method to resolve what method should i call later.
Maybe is there any other way to replace if-else statements more readable code, design patter or something more efficient?
I was thinking to combine whole possible states as flag enum values, but not sure if i can create enum value from object property later.
I think your best bet would be to ceate a Dictionary that would map your values to methods.
Now there are several options what could be the key in your dictionary - see below.
Disclaimer
Please also note that a big if statement is only an issue, if it is spread / duplicated across the codebase, and changes frequently - putting things in a dictionary does not really reduce complexity. Having methods in a dictionary also changes the semantics of your code. The first question should be - am I changing the mappings at runtime? Should they really be dynamic?
Dictionary with key ValueTuple struct you could use syntax (Shape, Color, Material) - this is the easiest one. Please note - not the Tuple class, but ValueTuple struct.
Dictionary with key Item class itself, but then you would need to take care about proper equality comparison in Item. You could make Item a struct to get that for free (but with slower performance, that comes from equality comparisons in System.ValueType that uses reflection in general case), or leave it as a class (or struct) and implement IEquatable<Item>, Equals and GetHashCode.
Without proper equality comparison, your dictionary lookup will not work (as suggested by #ckuri)
Use ValueTuple without a dictionary to simply condense your code.
A variation of the State pattern where you have a shared interface / base class for your handler. Handler is a separate class that contains one action for a specific set of values, like AnyBlueGlassHandler : Handler. Each handler checks the If condition, and when true, runs the actions. You could then put the handlers in a List<T> and apply them for an item like handlers.Foreach(x=>x.Handle(item))
The code when Item is the key could look like:
public static class ItemExtensions
{
static Dictionary<Item, Action<Item>>
methods = new Dictionary<Item, Action<Item>>()
{
{ new Item(Shape.any, Color.blue, Material.glass), x=> { /*do something*/ } }
};
public static bool TryApply(this Item item)
{
if (methods.TryGetValue(item, out var action))
{
action(item);
return true;
}
return false;
}
}
the code when ValueTuple is the key could look like
public static class ItemExtensionsUsingValueTuple
{
static Dictionary<(Shape, Color, Material), Action<Item>>
methods = new Dictionary<(Shape, Color, Material), Action<Item>>()
{
{ (Shape.any, Color.blue, Material.glass), x=> { /*do something*/ } }
};
public static bool TryApply(this Item item)
{
if (methods.TryGetValue((item.ItemShape, item.ItemColor, item.ItemMaterial), out var action))
{
action(item);
return true;
}
return false;
}
}
a more condensed version of your code with ifs, could look like:
declare Key property on your Item class
public (Shape, Color, Material) Key => (ItemShape, ItemColor, ItemMaterial);
use more elegant if statement
if ( item.Key == (Shape.any, Color.blue, Material.glass)) { }
It sounds like you want some rule set to check an item against.
I think the simplest form to make this more readable, is to pass the item, the properties of the rule, and the action to a separate method:
public bool RunActionIf(Item item, Shape shape, Color color, Material material, Action action)
{
if(item.ItemShape == shape && item.ItemColor == color && item.ItemMaterial == material)
{
action();
return true;
}
return false;
}
public void RunAction(Item item)
{
var result =
RunActionIf(item, Shape.square, Color.blue, Material.glass, Action1) ||
RunActionIf(item, Shape.square, Color.blue, Material.wood, Action2) ||
/* Implement your whole table like this */;
if(!result)
{
throw new ArgumentException("No matching rule found", nameof(item));
}
}
The main advantage of that method is that it's shorter and with less 'overhead' in the declaration. You can easily see: shape X + color Y + material Z= that action.
Another advantage is that it's easier to implement certain exceptions, for instance by allowing one of the rule parameters to be null to indicate any color, or to use Color.any to support that, although I think it's confusing to have any in the enum with other colors... Anyway, I digress. The point is, if you want to implement that, you have to do that only in one place without having to copy it 16 times.
You could abstract this away a bit further by making such a rule a separate object, which you can put in a list or dictionary, but for a definition like this, it doesn't make it that much more readable, although it does add some benefits of testibility, as well as the possibility to add different kinds of rules, without messing up your clean list again.
Try Dictionary<T>, for instance:
static Dictionary<Tuple<Shape, Color, Material>, Action> s_Actions = new
Dictionary<Tuple<Shape, Color, Material>, Action>() {
{Tuple.Create(Shape.square, Color.blue, Material.glass), () => { ... } },
...
{Tuple.Create(Shape.any, Color.red, Material.metal), () => { ... } },
...
};
private static void RunAction(MyItem item) {
Action action;
// Either exact match or match with Any
if (!s_Actions.TryGetValue(Tuple.Create(item.ItemShape, item.ItemColor, item.ItemMaterial),
out action))
action = s_Actions.FirstOrDefault(pair => pair.Key.Item1 == Color.any &&
pair.Key.Item2 == item.ItemColor &&
pair.Key.Item3 == item.ItemMaterial)
// Execute action if it's found
if (action != null)
action();
}
void RunAction((Shape shape, Color color, Material material) item)
{
switch(item)
{
case var i1 when i1.color == Color.red && i1.shape == Shape.square:
case var i2 when i2.color == Color.blue:
// Do action...
break;
case var i1 when i1.shape == Shape.trangle && i1.material == Material.metal:
// Do action...
break;
default:
// Do action...
break;
}
}
This solution uses Value Tuples, but primarily uses C#7 pattern matching in switch statements.
I don't think it totally solves your problem cleanly, but I think the multi-line cases gives you extra readability over the if statement approach and it's easy to implement.

C# FindIndex with parameters

I'm currently patching my game that i recently released.
I have a list of a class, which is called AppliedEffects. The list made from that class is named appliedEffects.
I want to access this list and find a specific value in an index, and then make a bool true or false depending of if that value exists in the list. It is for a powerup system, where the list is all the powerups currently active. The code for shooting bullets for instance, will then search if there is an item in the list with the ID of 1, because that is the ID of having the double bullets powerup.
I have come this far, and only have a small problem:
int ndx = PlayerStatus.appliedEffects.FindIndex(PlayerStatus.FindAE(XX,1);
where XX is, I don't know what to put. I edited this:
int ndx = Books.FindIndex(FindComputer);
private static bool FindComputer(Book bk)
{
if (bk.Genre == "Computer")
{
return true;
}
else
{
return false;
}
}
Because in the code example, I could not send in which parameter I wanted to search for. The edited code looks like this:
public static bool FindAE(AppliedEffects ae, int id)
{
if (ae.id == id)
{
return true;
}
else
{
return false;
}
}
I create an int, that will get the index of the list where the item with the value of ID 1 exists, then if that value is 1, because the ID is 1, it will set a bool to true, and false if not.
I wanted to send in a parameter for the ID, which the example does not, so that I can reuse the function for other ID checks. But then when I enter the parameter, I don't know what to put as appliedEffect (that's why I put XX).
I have also tried this:
if (PlayerStatus.appliedEffects.Exists(x => x.id == 1))
{
PlayerStatus.doubleBullets = true;
}
which did not work, no clue why. I don't fully understand the concepts of the .Exists and .FindIndex, so maybe that's why I don't know how to use it.
Basically I just want to be able to check if there is an item with a specific ID in the list, so that the game will know that I have the specific powerup and can set a bool to true and then false.
Note: ID is not index, ID is an int in my AppliedEffects class that knows which powerup it is.
I'm a little tired so if there's any thoughts/concerns, please write in the thread, I'll subscribe to the thread.
Note that FindIndex will return -1 if the requested element is not found. Therefore, you would have to do something like so:
if(PlayerStatus.appliedEffects.FindIndex(ae => PlayerStatus.FindAE(ae, 1)) != -1)
{
PlayerStatus.doubleBullets = true;
}
It would probably make more sense in your situation to use Exists, like you noted. Try this:
if(PlayerStatus.appliedEffects.Exists(ae => PlayerStatus.FindAE(ae, 1)))
{
PlayerStatus.doubleBullets = true;
}
int ndx = PlayerStatus.appliedEffects.FindIndex(ae => PlayerStatus.FindAE(ae, 1));
The parameter to FindIndex is a method/lambda with one argument. In this case, a lambda is created which takes a single parameter ae, and returns FindAE(ae, 1).
The FindAE method isn't necessary. It might be easier to do this:
int ndx = PlayerStatus.appliedEffects.FindIndex(ae => ae.index == 1);

If control in linq query entity framework

,Hi
List<Claimant> list = (from c in CacheManager.ClaimantList.List
where
c.Fullname.Replace("i", "İ").Replace("ı","I").ToUpper().Contains(searchKey.Replace("i", "İ").Replace("ı", "I").ToUpper())
|| c.IdentityNumber.Replace("i", "İ").Replace("ı", "I").ToUpper().Contains(searchKey.Replace("i", "İ").Replace("ı", "I").ToUpper())
|| c.TaxNumber.Replace("i", "İ").Replace("ı", "I").ToUpper().Contains(searchKey.Replace("i", "İ").Replace("ı", "I").ToUpper())
select c).Take(20).ToList<Claimant>();
If Taxnumber is null or "" i get exception because of null data.
My question:
How can i set Taxnumber == 0 , if Taxnumber is null or "" ?
Any help will be appreciated.
Thanks.
You can do:
from c in CacheManager.ClaimantList.List
let taxNumber = c.TaxNumber == null || c.TaxNumber == "" ? "0" : c.TaxNumber
where ...
and then use the taxNumber variable rather than the column.
If you just want certain columns and you don't need the whole Claimant object, you can put something into a select
from c in ClaimantList
where (...)
select new {c.FullName, c.IdentityNumber, TaxNumber = String.IsNullOrEmpty(c.TaxNumber) ? "0" : c.TaxNumber}
You now have an anonymous type with three fields: original FullName, original IdentityNumber and modified TaxNumber.
You could also create a new Claimant for each value by calling its constructor each time:
from c in ClaimantList
where (...)
select new Claimant() {FullName = c.FullName, IdentityNumber = c.IdentityNumber, TaxNumber = String.IsNullOrEmpty(c.TaxNumber) ? "0" : c.TaxNumber}
(I don't know what the constructor of Claimant is like, you might do this slightly differently and set those values in the constructor rather than in the initializer. Or you could write a new constructor.) If the constructor does something non-trivial, it might be wasteful of resources to call it this many times.
In either case, it is stylistically nice to put the conversion (String.IsNullOrEmpty(TaxNumber) ? "0" : TaxNumber or whatever) into its own function somewhere, so that you can change what conversion you do later (see below), and don't have to repeat the code in multiple places.
Another option is that you could use the objects you have, but change the TaxNumber as required. LINQ isn't really the best way of doing this, as you are basically applying side-effects. (LINQ likes to supply a new container with the right data in it, rather than change the data in the original container.) You should really run foreach outside of the Linq code, like this:
List<Claimant> list = from ...
where ...
select ...
foreach (Claimant claimant in list)
{
if (String.IsNullOrEmpty(claimant.TaxNumber))
{ claimant.TaxNumber = "0"; }
}
Ideally you do this after the Take(20) so that you only do it the number of times you need.
Again, putting the conversion in a function will be neater and nicer:
List<Claimant> list = from ...
where ...
select ...
foreach (Claimant claimant in list)
{
claimant.TaxNumber = NormalizeTaxNumber(claimant.TaxNumber); }
}
// ...
public static string NormalizeTaxNumber(string n)
{
return String.IsNullOrEmpty(n) ? "0" : n;
}
However, if you have gone down this route, the next option is to add a method to Claimant which does this change:
List<Claimant> list = from ...
where ...
select ...
foreach (Claimant claimant in list)
{
claimant.NormalizeTaxNumber();
}
public class Claimant
{
// ...
public void NormalizeTaxNumber()
{
if (String.IsNullOrEmpty(TaxNumber))
{ TaxNumber = "0"; }
}
}
and to call this from the foreach loop.
Or, use a different property than TaxNumber:
public class Claimant
{
// ...
public string NormalTaxNumber
{
get { return String.IsNullOrEmpty(TaxNumber) ? "0" : TaxNumber; }
}
}
The advantage of the first strategy is that you only have to call it once - the advantages of the second are that it keeps the original value still available (in the TaxNumber property), and that if you have a bunch of Claimant objects, you don't have to remember whether you have normalized them or not.
You could also use a combination of the two methods: add a new property NormalTaxNumber which converts TaxNumber when needed, and which caches the result so that conversion doesn't have to be done again.
public class Claimant
{
// ...
private string m_normalTaxNumber;
private string ConvertedTaxNumber
{
get { return String.IsNullOrEmpty(TaxNumber) ? "0" : TaxNumber; }
}
public string NormalTaxNumber
{
get
{
if (m_normalTaxNumber == null)
{ m_normalTaxNumber = ConvertedTaxNumber; }
return m_normalTaxNumber;
}
}
}
This only does the calculation once, keeps the original still available, and doesn't require to remember if you've called it before or not. If TaxNumber (the original value) isn't readonly, this is probably more trouble than it's worth as you will have to invalidate the cached value.
If you are never, never going to need to know whether the TaxNumber was originally null, empty or "0", the best advice (and the last strategy) is to convert to the form you want as soon as possible, preferably in the Claimant constructor, if the value of TaxNumber is known there.
If you are getting Claimant objects from a database, you could take this to its logical limit by doing the conversion on the database, either in a stored proc or in a view. If you are using LinqToSql to get the list of Claimant objects, a view could work for you but a stored proc might not.
I have assumed throughout that you want TaxNumber to be available as a string, and that by 0 you mean the string "0". If this isn't the case, and you actually want convert to an int (or similar), some of the strategies above will still work. You can select the converted value as an int in an anonymous type, you can make a new property NormalTaxNumber (with int type), whether cached or not cached, or you can do the conversion upon creation of a Claimant object. Obviously you can't overwrite the string TaxNumber with an int.
If you are parsing the string to an int, things like NormalTaxNumber with caching become more worthwhile, because the conversion from string to int is more costly. (Checking for null or "" is actually very fast, however I thought it valuable to go through some different options anyway.)
Note that almost all of these should still be available to you if you can't modify the Claimant class. You can't write a new constructor, but you can write a factory method which encapsulates exactly the same behavior as a constructor. You can add NormalizeTaxNumber as an extension method, and while you can't add properties, you can add extension methods with no arguments which work almost exactly like properties.
My last observation is that "0" might not necessarily be a better value for missing data than null or "". Either of the latter is more commonly used to indicate missing values, especially null. Perhaps you should choose one of those as the default (and maybe apply one of the above strategies in reverse to enforce it as the only 'N/A' value?) If it's just a question of it looking nice when you print the object out, you could override ToString() to swap in the "0" only when needed.

What options do i have to make this code thread safe?

I have this segment of code , a lot of things skipped for brevity but the scene is this one:
public class Billing
{
private List<PrecalculateValue> Values = new List<PrecalculateValue>();
public int GetValue(DateTime date)
{
var preCalculated = Values.SingleOrDefault(g => g.date == date).value;
//if exist in Values, return it
if(preCalculated != null)
{
return preCalculated;
}
// if it does not exist calculate it and store it in Values
int value = GetValueFor(date);
Values.Add(new PrecalculateValue{date = date, value = value});
return value;
}
private object GetValueFor(DateTime date)
{
//some logic here
}
}
I have a List<PrecalculateValue> Values where i store all the values i already calculated for later use, i do these mainly because i don't want to recalculate things twice for the same client, each calculation involve a lot of operations and take between 500 and 1000 ms, and there is a big chance of reuse that value, because of some recursion involved in the hole billing class.
All of these work perfectly until i made a test where i hit two simultaneous calculations for two different clients, and the line Values.Single(g => g.date == date).value returned an exception because it found more than one result in the collection.
So i checked the list and it stored values of both clients in the same list. What can i do to avoid this little problem?
Well, first of all, this line:
return Values.Single(g => g.date == date).value;
makes it so that the subsequent lines will never be called. I'm guessing you've paraphrased your code a little bit here?
If you want to synchronize writes to your Values list, the most straightforward way would be to lock on a common object everywhere in the code that you're modifying the list:
int value = GetValueFor(date);
lock (dedicatedLockObject) {
Values.Add(new PrecalculateValue{date = date, value = value});
}
return value;
But here's something else worth noting: since it looks like you want to have one PrecalculateValue per DateTime, a more appropriate data structure would probably be a Dictionary<DateTime, PrecalculateValue> -- it will provide lightning-fast, O(1) lookup based on your DateTime key, as compared to a List<PrecalculateValue> which would have to iterate to find what you're looking for.
With this change in place, your code might look something like this:
public class Billing
{
private Dictionary<DateTime, PrecalculateValue> Values =
new Dictionary<DateTime, PrecalculateValue>();
private readonly commonLockObject = new object();
public int GetValue(DateTime date)
{
PrecalculateValue cachedCalculation;
// Note: for true thread safety, you need to lock reads as well as
// writes, to ensure that a write happening concurrently with a read
// does not corrupt state.
lock (commonLockObject) {
if (Values.TryGetValue(date, out cachedCalculation))
return cachedCalculation.value;
}
int value = GetValueFor(date);
// Here we need to check if the key exists again, just in case another
// thread added an item since we last checked.
// Also be sure to lock ANYWHERE ELSE you're manipulating
// or reading from the collection.
lock (commonLockObject) {
if (!Values.ContainsKey(date))
Values[date] = new PrecalculateValue{date = date, value = value};
}
return value;
}
private object GetValueFor(DateTime date)
{
//some logic here
}
}
And one last piece of advice: unless it's critical that no more than one of a particular value exist in your collection, the Single method is overkill. If you'd rather just get the first value and disregard potential duplicates, First is both safer (as in, less chance of an exception) and faster (because it doesn't have to iterate over the entire collection).
Could use something like this
public int GetValue(DateTime date)
{
var result = Values.Single(g => g.date == date) ?? GetValueFor(date);
lock (Values)
{
if (!Values.Contains(result)) Values.Add(result);
}
return result.value;
}
private PrecalculateValue GetValueFor(DateTime date)
{
//logic
return new PrecalculateValue() ;
}
Would advise using a dictionary though for a list of key value pairs.

Categories