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.
Related
I need to compare two objects of the same type but with a lot of prop
return string.Equals(x.Name, y.Name) &&
x.Price == y.Price &&
string.Equals(x.Species, y.Species) &&
x.AgeEnforced == y.AgeEnforced &&
x.MinimumAge == y.MinimumAge &&
string.Equals(x.WeightRange, y.WeightRange) &&
x.MinimumWeight == y.MinimumWeight
The list goes on up to 14 props
A hint on how can I lose && operator?
If your class has 14 properties and all of them have to be compared to ensure equality, all of these checks have to be made somewhere. No matter if you put them into a (maybe static) helper method, the Equals-method, a class that implements IEqualityComparer (IMHO the best choice), an extension method or whatever else comes to your mind, you have to write down all of these checks once.
Instead of writing these checks on yourself you can use some reflection stuff (or a library that makes use of it) by iterating over all properties, but that's normally not the best choice, cause it is slower and equality checks are tend to be called very often (sort, hashset, etc.). So take the pain and write the checks down.
If you think these are too many checks, then maybe your object is to fat and has to much properties. Maybe it needs a deeper hierarchy by using classes which are representing a part of the whole thing and you have a top class that has as property a child class and then you write the compare method for each child class individually and the top class just calls these comparers for its child classes.
Answer to A hint on how can i lose && operator?
if (string.Equals(x.Name, y.Name) == false) return false;
if (x.Price != y.Price) return false
// ... others
return true;
This code must be somewhere. If this is only place where this code exist this is ok in my opinion. Bu if it exists in many places then you can move it to some helper fuction or override Equals() method in your object. MSDN info.
Example how to oveeride and use Equals():
public class MyObject
{
public string Name { get; set; }
public decimal Price { get; set; }
public override bool Equals(object obj)
{
MyObject o = obj as MyObject;
if (o == null)
return false;
if (this.Name != o.Name)
return false;
return true;
}
/// <summary>
/// Serves as the default hash function.
/// </summary>
/// <returns>
/// A hash code for the current object.
/// </returns>
public override int GetHashCode()
{
return base.GetHashCode();
}
}
public class Program
{
static public void Main()
{
MyObject o1 = new MyObject()
{
Name = "a",
Price = 1
};
MyObject o2 = new MyObject()
{
Name = "b",
Price = 1
};
MyObject o3 = new MyObject()
{
Name = "a",
Price = 1
};
Console.WriteLine("o1 == o2: {0}", o1.Equals(o2));
Console.WriteLine("o1 == o3: {0}", o1.Equals(o3));
Console.ReadKey();
}
}
Result is:
o1 == o2: False
o1 == o3: True
For me, && or || are pretty short already. Your problem lies not in the operator itself, but in the way you are doing the comparison of 14+ properties.
Instead of writing all the property-comparisons by hand, you can try automating it.
var props_string = new List<Func<MyObject, string>>();
props_string.Add(foo => foo.Name);
props_string.Add(foo => foo.Species);
//..
var props_double = new List<Func<MyObject, double>>();
props_double.Add(foo => foo.Price);
//..
Now, having them listed, you can ran a loop over it
MyObject first = ...;
MyObject second = ...;
bool areEqual = true;
foreach(var prop in props_string)
if(!string.Equals(prop(first), prop(second)))
areEqual = false;
foreach(var prop in props_double)
if(prop(first) != prop(second))
areEqual = false;
return areEqual;
The positive side is that even if there were 100 properties, one or two (or more) loops would fly over it.
Please note that this code is not optimized and pretty naive.
More natural would be a fast-exit on first difference:
foreach(var prop in props_double)
if(prop(first) != prop(second))
return false;
..and/or observing that string.equals and double!=double can all be packed as the same object.Equals method (so you don't need separate props_string, props_double etc)
..and/or observing that you don't really need to list all properties, you can get them from Reflection, so you don't need to 'define' the 100 properties in these lists. (But then, you often have some special properties that you don't want to include.. so your reflection-way would need a way to detect and skip them..)
..and/or observing that if you used struct instead of class you would get full memberwise object.Equals comparison for free. (But then, structs differ from classes in many other things..)
..and/or(...)
All these 'optimizations' are highly dependent on what you have in the rest of the 14+ comparisons. It looks fun and smart at first, but the more the types of properties vary and the more types of comparisons you need to do (string.equals with case-insensitive maybe?) the worse it will get. Sometimes 14 times &&, or 14 times if(x==y)return false isn't really that bad.
Please don't get me wrong: I do not advise you to use the way I show here. I just show you that it is possible. Don't use it unless absolutely relevant and necessary. Doing it this way may cost you much more time than you would want to.
This seems as a correct way how to do the compare.
If your aim is to be able to easily check if two different instances are equal you can override Equals() and GetHashCode().
You will be able to do:
x.Equals(y)
You can also override operator ==. In which case you can do:
x == y
Check MSDN for details and example.
Also there is no reason for you (unless you want to use any extra parameters) to use
string.Equals(x.Name, y.Name)
use simply
x.Name == y.Name
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");
}
}
I'm working on the architecture for what is essentially a document parsing and analysis framework. Given the lines of the document, the framework will ultimately produce a large object (call it Document) representing the document.
Early filters in the pipeline will need to operate on a line-by-line basis. However, filters further down will need to transform (and ultimately produce) the Document object.
To implement this, I was thinking of using a filter definition like this:
public interface IFilter<in TIn, out TOut> {
TOut Execute(TIn data);
}
All filters will be registered with a PipelineManager class (as opposed to using the 'linked-list' style approach.) Before executing, PipelineManager will verify the integrity of the pipeline to ensure that no filter is given the wrong input type.
My question: Is it architecturally sound to have a pipeline with a changing data type (i.e. a good idea)?
P.S. The reason I'm implementing my application as a pipeline is because I feel it will be easy for plugin authors to replace/extend existing filters. Just swap out the filter you want to change with a different implementation, and you're set.
EDIT: Note, have removed other answer to replace with this wall'o'text grin
NINJAEDIT: Fun fact: Powershell (mentioned in #Loudenvier's answer) was once going to be named 'Monad' - also, found Wes Dyer's blog post on topic: The Marvels of Monads
One veryveryvery simplistic way of looking at this whole "Monad" thing is to think of it as a box with a very basic interface:
Return
Bind
Zero (optional)
The uses are similarly simple in concept - let's say you have a "thing":
You can wrap your "thing" in the box (this would be the "return") and have a "BoxOfThing"
You can give instructions on how to take the thing out of this box and put it into another box (Bind)
You can get an empty box (the "Zero": think of it as a sort of "no-op", like multiplying by one or adding zero)
(there are other rules, but these three are the most interesting)
The Bind bit is the really interesting part, and also the part that makes most people's heads explode; basically,
you're giving a specification of sorts for how to chain boxes together: Let's take a fairly simple Monad, the "Option"
or "Maybe" - a bit like Nullable<T>, but way cooler.
So everybody hates checking for null everywhere, but we're forced to due to the way reference types work; what we'd love
is to be able to code something like this:
var zipcodesNearby = order.Customer.Address.City.ZipCodes;
And either get back a valid answer if (customer is valid + address is valid + ...), or "Nothing" if any bit of that logic fails...but
no, we need to:
List<string> zipcodesNearBy = new List<string>();
if(goodOrder.Customer != null)
{
if(goodOrder.Customer.Address != null)
{
if(goodOrder.Customer.Address.City != null)
{
if(goodOrder.Customer.Address.City.ZipCodes != null)
{
zipcodesNearBy = goodOrder.Customer.Address.City.ZipCodes;
}
else { /* do something else? throw? */ }
}
else { /* do something else? throw? */ }
}
else { /* do something else? throw? */ }
}
else { /* do something else? throw? */ }
(note: you can also rely on null coalescing, when applicable - although it's pretty nasty looking)
List<string> nullCoalescingZips =
((((goodOrder ?? new Order())
.Customer ?? new Person())
.Address ?? new Address())
.City ?? new City())
.ZipCodes ?? new List<string>();
The Maybe monad "rules" might look a bit like:
(note:C# is NOT ideal for this type of Type-mangling, so it gets a bit wonky)
public static Maybe<T> Return(T value)
{
return ReferenceEquals(value, null) ? Maybe<T>.Nothing : new Maybe<T>() { Value = value };
}
public static Maybe<U> Bind<U>(Maybe<T> me, Func<T, Maybe<U>> map)
{
return me != Maybe<T>.Nothing ?
// extract, map, and rebox
map(me.Value) :
// We have nothing, so we pass along nothing...
Maybe<U>.Nothing;
}
But this leads to some NASTY code:
var result1 =
Maybe<string>.Bind(Maybe<string>.Return("hello"), hello =>
Maybe<string>.Bind(Maybe<string>.Return((string)null), doh =>
Maybe<string>.Bind(Maybe<string>.Return("world"), world =>
hello + doh + world).Value
).Value
);
Luckily, there's a neat shortcut: SelectMany is very roughly equivalent to "Bind":
If we implement SelectMany for our Maybe<T>...
public class Maybe<T>
{
public static readonly Maybe<T> Nothing = new Maybe<T>();
private Maybe() {}
public T Value { get; private set;}
public Maybe(T value) { Value = value; }
}
public static class MaybeExt
{
public static bool IsNothing<T>(this Maybe<T> me)
{
return me == Maybe<T>.Nothing;
}
public static Maybe<T> May<T>(this T value)
{
return ReferenceEquals(value, null) ? Maybe<T>.Nothing : new Maybe<T>(value);
}
// Note: this is basically just "Bind"
public static Maybe<U> SelectMany<T,U>(this Maybe<T> me, Func<T, Maybe<U>> map)
{
return me != Maybe<T>.Nothing ?
// extract, map, and rebox
map(me.Value) :
// We have nothing, so we pass along nothing...
Maybe<U>.Nothing;
}
// This overload is the one that "turns on" query comprehension syntax...
public static Maybe<V> SelectMany<T,U,V>(this Maybe<T> me, Func<T, Maybe<U>> map, Func<T,U,V> selector)
{
return me.SelectMany(x => map(x).SelectMany(y => selector(x,y).May()));
}
}
Now we can piggyback on LINQ comprehension syntax!
var result1 =
from hello in "Hello".May()
from oops in ((string)null).May()
from world in "world".May()
select hello + oops + world;
// prints "Was Nothing!"
Console.WriteLine(result1.IsNothing() ? "Was Nothing!" : result1.Value);
var result2 =
from hello in "Hello".May()
from space in " ".May()
from world in "world".May()
select hello + space + world;
// prints "Hello world"
Console.WriteLine(result2.IsNothing() ? "Was Nothing!" : result2.Value);
var goodOrder = new Order { Customer = new Person { Address = new Address { City = new City { ZipCodes = new List<string>{"90210"}}}}};
var badOrder = new Order { Customer = new Person { Address = null }};
var zipcodesNearby =
from ord in goodOrder.May()
from cust in ord.Customer.May()
from add in cust.Address.May()
from city in add.City.May()
from zip in city.ZipCodes.May()
select zip;
// prints "90210"
Console.WriteLine(zipcodesNearby.IsNothing() ? "Nothing!" : zipcodesNearby.Value.FirstOrDefault());
var badZipcodesNearby =
from ord in badOrder.May()
from cust in ord.Customer.May()
from add in cust.Address.May()
from city in add.City.May()
from zip in city.ZipCodes.May()
select zip;
// prints "Nothing!"
Console.WriteLine(badZipcodesNearby.IsNothing() ? "Nothing!" : badZipcodesNearby.Value.FirstOrDefault());
Hah, just realized I forgot to mention the whole point of this...so basically, once you've figured out what the equivalent for "bind" is at each stage of your pipeline, you can use the same type of pseudomonadic code to handle the wrapping, unwrapping, and processing of each of your type transformations.
This won't answer your question, but a great place to look for inspiration on pipelines in the .NET world is PowerShell. They've implemented the pipeline model in a very clever way, and the objects flowing the pipeline will change all the time.
I've had to produce a Database to PDF document creation pipeline in the past and did it as PowerShell commandlets. It was so extensible that years later it is still being actively used and developed, it only migrated from PowerShell 1 to 2 and now possibly to 3.
You can get great ideas here: http://blogs.technet.com/b/heyscriptingguy/
Given the following code, is there a better way to structure this?
foreach(Thing item in SomeRandomList)
{
bool firstCondition = CalculateBool(item, someValue);
bool secondCondition = CalculateBool(item, someOtherValue);
//General things are done...
if(firstCondition || secondCondition)
{
//semi-specific things are done...
if(firstCondition)
{
//specific things are done...
}
else
{
//specific things are done...
}
}
}
Also, what if there are more conditions, i.e. 3:
foreach(Thing item in SomeRandomList)
{
bool firstCondition = CalculateBool(item, someValue);
bool secondCondition = CalculateBool(item, someOtherValue);
//imagine as many more as you want.
bool nthCondition = CalculateBool(item, lastOtherValue);
//General things are done...
if(firstCondition || secondCondition || nthCondition)
{
//semi-specific things are done...
if(firstCondition)
{
//specific things are done...
}
else if(secondCondition)
{
//specific things are done...
}
else
{
//specific things are done...
}
}
}
Yes: Polymorphism.
Derive Thing's from a common base (or define an Interface that all Thing's implement)
Failing that, move the conditional testing code into a method on Thing.
If you can do the semi-specific things after the specific ones, you could try this:
bool anyTrue = true;
if (firstCondition)
{
// Specific things
}
else if (secondCondition)
{
// Specific things
}
else
{
// Specific things
anyTrue = false;
}
if (anyTrue)
{
// Semi-specific things
}
I don't know if it's necessarily better, but it's different...
Alternatively, I'm not all up on C# 3.0 and the fancy new LINQ stuff, but if its expressive enough you could try something like (pseudo-code):
bool[] conditions =
{
CalculateBool(item, someValue),
CalculateBool(item, someOtherValue),
...
};
if (conditions.AnyTrue)
{
switch (conditions.IndexOfFirstTrueItem)
{
case 0:
// Specific things
break;
case 1:
// Specific things
break;
default:
// Specific things
break;
}
}
I'd use some LINQ to use an intermediate query to help reduce the logic in the loop:
// Get condition in the query.
var query =
from item in SomeRandomList
let condition1 = CalculateBool(item, someValue1)
let condition2 = CalculateBool(item, someValue2)
...
let conditionN = CalculateBool(item, someValueN)
where
condition1 || condition2 || ... || conditionN
select new { Item = item,
Condition1 = condition1, Condition1 = condition2, ...
ConditionN = conditionN };
foreach(var item in query)
{
//semi-specific things are done...
if(firstCondition)
{
//specific things are done...
}
else
{
//specific things are done...
}
}
Hopefully, this will reduce the amount of code in the loop tremendously.
It seems to me though that you have a sequence of values that are being passed to CalculateBool for each item in SomeRandomList. If that is the case, then you could easily generate a query which does a cross join and filter on that:
// Get all valid items across all values.
var query =
from item in SomeRandomList
from value in someValues
where CalculateBool(item, value)
select { Item = item, Value = value };
// Iterate and process.
foreach (var item in query)
{
// Use item.Item and item.Value.
// Specifically, use item.Value to perform a lookup
// in a map somewhere to determine the course of action
// instead of a giant switch statement.
}
This would work because your conditionals indicate that you would only have one value set for each item.
I like the approach of having a dictionary of Predicate<T> and their associated Actions. I answered a similar question here:
Coming out of the habit of writing ifs/elseifs for every possible condition
To modify it a bit for your question:
Dictionary<Predicate<Something>, Action> mappings = {{...}}
bool shouldDoAnything = mappings.Keys.Aggregate(true, (accum, condition) =>
accum || condition);
if (shouldDoAnything)
{
//do semi-specific things
foreach(DictionaryEntry<Predicate<Something>, Action> mapping in mappings)
{
if (mapping.Key(input))
{
mapping.Value(); //do specific things
break;
}
}
}
foreach(Thing item in SomeRandomList)
{
DoGeneralThings(); //pass in whatever your require to the method
if(FirstCondition(item, someValue))
{
DoThingsWhenAnyConditionIsTrue(); //pass in whatever your require to the method
DoSpecificThingsForFirstCondition(); //pass in whatever your require to the method
continue;
}
if(SecondCondition(item, someValue))
{
DoThingsWhenAnyConditionIsTrue(); //pass in whatever your require to the method
DoSpecificThingsForSecondCondition(); //pass in whatever your require to the method
continue;
}
}
I might have not been able to get the question right, we can only have 2 results, if function has return type bool not n results, unless it is Nullable<bool>, which could return null as well.
so
bool result = CalculateBool(item, someValue);
if(result) {}
else {}
will do it.
about managing large if / else combination ? One way is to use Switch statement, that could increase readability.
But in any case, a method should always have least possible decision paths, this is known as
cyclomatic complexity.
If this happens, split the code into more appropriate methods
When trying to use delegates in C# to solve a problem in a functional way, I've come across a pitfall that I want to share resp. for which I would like to hear your suggestions.
Background
I want to fill a grid from a list of objects where the values for single columns are get using delegates (idea borrowed from Philip Pipers ObjectListView control).
Additionally I want to automatically insert columns containing the (numerical) difference between two values.
So my objects having properties FirstValue, SecondValue and ThirdValue I want to have columns with FirstValue, (SecondValue-FirstValue), SecondValue, (ThirdValue-SecondValue), ThirdValue.
I already have adapted an existing grid control to use delegates on an object list, this part works fine.
First attempt
First, I tried something like:
class MyGridClass : DelegateGrid
{
DelegateGrid.ValueGetter lastGetter;
public MyGridClass() {
AddMyColumn(delegate(MyObj obj) { return obj.FirstValue; });
AddMyColumn(delegate(MyObj obj) { return obj.SecondValue; });
AddMyColumn(delegate(MyObj obj) { return obj.ThirdValue; });
}
private void AddMyColumn(DelegateGrid.ValueGetter getter) {
if (lastGetter != null)
base.AddColumn(new DelegateColumn(delegate(MyObj obj) {
return getter(obj)-lastGetter(obj);
}));
base.AddColumn(new DelegateColumn(getter));
}
};
Problem
In a functional language, calculating the difference in this way would work fine, since the new delegate (constructed inside AddMyColumn) would use the value of lastGetter at the time of construction. But in C#, the new delegate uses a reference to lastGetter, so when executed, it uses the actual value at the time of execution. So the difference will always be built against the last column (i.e. obj.ThirdValue).
Solution
One solution I've found for myself is
public AddMyColumn(DelegateGrid.ValueGetter getter) {
if (lastGetter != null) {
DelegateGrid.ValueGetter newLastGetter =
new DelegateGrid.ValueGetter(lastGetter);
base.AddColumn(new DelegateColumn(delegate(MyObj obj) {
return getter(obj)-newLastGetter(obj);
}));
}
// ...
}
Note that
if (lastGetter != null) {
DelegateGrid.ValueGetter newLastGetter =
delegate(MyObject obj){return lastGetter(obj); };
wouldn't have solved the problem.
Question
Already having found a solution, this part is a bit pro forma, but
Does anyone have a suggestion for a better solution
I'm using C#2.0 and have only a theoretical knowledge of lambda expressions in C#3.0: Would they allow for a cleaner solution (and thus deserve their name...)?
The problem is just that the variable is being captured rather than the value. Here's a solution which is much the same, but slightly simpler:
public AddMyColumn(DelegateGrid.ValueGetter getter) {
if (lastGetter != null) {
DelegateGrid.ValueGetter newLastGetter = lastGetter;
base.AddColumn(new DelegateColumn(delegate(MyObj obj) {
return getter(obj)-newLastGetter(obj);
}));
}
// ...
}
Basically there's no need to create a new delegate instance - delegates are immutable, so you can just copy the value with assignment.
This isn't really a delegate-specific problem in terms of the value being captured - it's a common problem for anonymous methods and lambda expressions in general. The typical example is;
List<Action> actions = new List<Action>();
for (int i=0; i < 10; i++)
{
actions.Add(() => Console.WriteLine(i));
}
foreach (Action action in actions)
{
action();
}
This prints "10" 10 times. To print 0-9, you again need to change the scope of the captured variable:
List<Action> actions = new List<Action>();
for (int i=0; i < 10; i++)
{
int copy = i;
actions.Add(() => Console.WriteLine(copy));
}
foreach (Action action in actions)
{
action();
}
To answer your other points, lambda syntax is going to make it much nicer, since they'll reduce the verbose code.
delegate(MyObj obj) {
return getter(obj)-newLastGetter(obj);
}
Becomes:
obj => getter(obj)-newLastGetter(obj)