I have a very lengthy boolean variable which looks something like:
c.Card != null && slot.Card.CardId == c.Card.CardId && slot.E1Number == c.E1Number && slot.Capacity == c.Capacity && slot.PacketLinkCapacity == c.PacketLinkCapacity && slot.TrafficType == c.TrafficType && slot.TxFrequency == c.RxFrequency && slot.RxFrequency == c.TxFrequency && slot.E1Number != null && slot.Capacity != null && slot.ProtectionMode == c.ProtectionMode
Since this condition needs to be checked frequently I keep writing the same thing over and over again. Is it possible to store this in a variable so I can just reuse that whenever I need?
Yes, you can. Just create a method that does this check, or if you want to pass that function around, use Func<bool>:
Func<bool> f = new Func<bool>( () => YourLengthyMethod() );
Try something like this:
private static Expression<Func<Slot, bool>> Filter(filter)
{
return cat => [...your code for filtering...];
}
I would recommend you to separate this and write it to another method that you will call it when you want to do all these checks. It's not good practice to have repeated code in your project.
For example, in your case, you can give as parameters to this method the info (c.Card, slot.Card.CardId etc) and do the right checking over there.
Smart(ish) usage of C# features:
class EvaluatedBoolean
{
private readonly Func<bool> _evaluation = () => false;
public EvaluatedBoolean(Func<bool> evaluation)
{
_evaluation = evaluation;
}
public static implicit operator bool(EvaluatedBoolean eb)
{
return eb._evaluation.Invoke();
}
}
Then:
var eval = new EvaluatedBoolean(() => /*your conditions here*/);
...
PerformSomeWorkIfCondition(eval);
...
void PerformSomeWorkIfCondition(bool condition)
{
if (condition)
{
//do something
...
Related
I have some code written in C# for which I need to add some conditions. From one of my methods, I'm calling another method "UpdateData()", which updates some data into the database. Now for this, I need to add some conditions.
There will be appsetting in the config file, which is a boolean value. If the value is true, then the conditions in point2 have to be checked, if the value is false, it has to directly call UpdateData() method.
There are few types and statuses which needs be checked if the point1 is true.
Condition 1: If type is 'A' and status is "Complete" - then call "UpdateData()".
Condition 2 : If type is 'B' and status is "Complete" or "Partial" or "some xyz" - then call "UpdateData()".
So for this I have written the below code :
bool checkStatus = Convert.ToBoolean(ConfigurationManager.AppSettings["CheckStatus"]);
if (checkStatus)
{
if (type == "A" && status == "Complete")
{
UpdateData();
}
else if (type == "B" && (status == "Complete" || status == "Other status" || status == "someother status"))
{
UpdateData(); // for type B , data should not be updated if status is anything other than those in condition.
}
}
else
{
UpdateData();
}
This is working as expected. But I do not want to write nested if-else. If tomorrow there is some other status and type I need to include, I need to add another if condition here.
Is there any better or optimized way of writing it?
I personally think what you have is fine. However, if you really don't like it, you could fiddle with local methods i guess
bool CheckA() => type == "A" && status == "Complete";
bool CheckB() => type == "B" && (status == "Complete" || status == "Other status" || status == "someother status")
if (!checkStatus || CheckA() || CheckB())
UpdateData();
or
bool Check(string val, params string[] list) => type == val && list.Contains(status);
// uglay, yet approachable
if (!checkStatus ||
Check("A", "Complete") ||
Check("B", "Complete", "Other status", "someother status"))
{
UpdateData();
}
Note : I personally wouldn't do these, though it might be your cup of tea
If it is to optimise the ability to add a new one quickly, I would've put it in an array.
bool[] checks = new bool[]{
(type == "A" && status == "Complete"),
(type == "B" && (status == "Complete" || status == "Other status" || status == "someother status"))
}
if (!checkStatus || checks.Contains(false)) //'Contains' requires Linq, it also works with 'checks.Any(c => !c)'
{
UpdateData();
}
This way you only need to add a new condition in the bool array and you don't have to update the if-statement for it. And you can comment out one quickly if you don't need it.
Though, it's usefulness depends on how many conditions you may expect to add.
I guess the main point of this code is to ensure the update runs when the conditions are met, which is done via unit testing.
So, I would look at how I could write this code in a testable manner so I can be sure that it does what it says on the tin.
One way to do it could be something like this:
public bool AppSettingsRunStatusMet(string appSettingsCheckStatus)
{
return Convert.ToBoolean(appSettingsCheckStatus);
}
public bool TypeARunStatusMet(string type, string status)
{
return (type.Equals("A") && status.Equals("Complete"))
}
public bool TypeBRunStatusMet(string type, string status)
{
return (
type.Equals("B") &&
(
status.Equals("Complete") ||
status.Equals("Other status") ||
status.Equals("someother status")
)
}
This is starting to shape up as a rules engine and you can have as many rules as you need
each if statement can now call one method and each rule is separated in its own method which can now be easily tested properly.
You could put all rules in their own class(es), have the engine return a status and if that status is true then run the update. The main idea is to separate config code, from the status analysis and from the code which runs the update and does whatever it is it needs to do.
I'd prefer doing something like this, so that when new cases shows up or validation criteria changes we can just whitelist new case. This is simple/maintainable, works well for growing set of valid_cases with little changes.
using System;
using System.Collections.Generic;
public class Program
{
class Case{
string type;
string status;
public Case(string type_val, string status_val ){
status = status_val;
type = type_val;
}
public override int GetHashCode()
{
return type.GetHashCode()+status.GetHashCode();
}
public override bool Equals(object obj)
{
Case test = obj as Case;
if (test== null)
return false;
return type == test.type && status == test.status ;
}
}
public static void Main()
{
bool checkStatus = true;
HashSet<Case> vaild_cases = new HashSet<Case>();
vaild_cases.Add(new Case("A","Complete"));
vaild_cases.Add(new Case("B","Complete"));
vaild_cases.Add(new Case("B","Other status"));
vaild_cases.Add(new Case("B","someother status"));
Case current_case = new Case("A","Complete");
if (!checkStatus || vaild_cases.Contains(current_case))
UpdateData();
}
static void UpdateData()
{
Console.WriteLine("Hello, World!");
return;
}
}
Cheers !!
Another option is this:
if((new string[] {"Complete", "Other status", "someother status"}.Contains(status) && type == "B") ||
(status == "Complete" && type == "A") ||
!checkStatus)
{
UpdateData();
}
I have the following nested if clause, I was wondering if I, by applying some pattern, can simplify it?
The code checks to see if it needs an authorizationStartDate, and if it does, but does not have it, returns true.
I've considered the Strategy Pattern, the "Replace conditional with polymorphism" method, the Specification Pattern and various others, but I haven't found anything which I liked.
private bool IsMissingAuthorizationStartDate(ApplicationStatusData data)
{
if (data.ApplicationStatus == ApplicationStatusType.ApplicationApproved)
{
if (data.ApplicationPurpose == ApplicationPurpose.New)
{
if (data.ProductStatus?.ProductStatusType == ProductStatusType.ApplicationForNewProductReceived)
{
if (data.ApplicationTypePesticide == ApplicationTypePesticide.Authorisation ||
data.ApplicationTypePesticide == ApplicationTypePesticide.ProvisionalAuthorisation ||
data.ApplicationTypePesticide == ApplicationTypePesticide.MutualRecognition ||
data.ApplicationTypePesticide == ApplicationTypePesticide.Derogation ||
data.ApplicationTypePesticide == ApplicationTypePesticide.DispensationPreviousAssessment ||
data.ApplicationTypePesticide == ApplicationTypePesticide.ResearchAndDevelopmentPurposesExperimentOrTestProgram ||
data.ApplicationTypePesticide == ApplicationTypePesticide.ResearchAndDevelopmentPurposesExperimentOrTestProgramKnownProduct ||
data.ApplicationTypePesticide == ApplicationTypePesticide.ParallelTradePermit ||
data.ApplicationTypePesticide == ApplicationTypePesticide.Copy
)
{
if (!data.AuthorizationStartDate.HasValue)
{
return true;
}
}
}
}
else if (data.ApplicationPurpose == ApplicationPurpose.Renewal)
{
if (data.ProductStatus.ProductStatusType == ProductStatusType.ProductAuthorised)
{
if (data.ApplicationTypePesticide == ApplicationTypePesticide.ReAuthorisation ||
data.ApplicationTypePesticide == ApplicationTypePesticide.ParallelTradePermit ||
data.ApplicationTypePesticide == ApplicationTypePesticide.Copy
)
{
if (!data.AuthorizationStartDate.HasValue)
{
return true;
}
}
}
}
}
// else
return false;
}
The pattern I would use here is just encapsulation. The nesting here is hard to follow, and worsened by the equality comparisons. If possible, instead of exposing the raw field, try encapsulating the intent.
e.g. Instead of if (data.ApplicationPurpose == ApplicationPurpose.Renewal) try extending ApplicationStatusData with a property like
bool IsRenewalApplication
{
get
{
return this.ApplicationPurpose == ApplicationPurpose.Renewal;
}
}
so your code reads cleaner, with more expression: if (data.IsRenewalApplication) { ... }
Particularly where you have that massive if this or that or that or that, put it under a well-named property like IsInterestingPesticide.
If you can't change ApplicationStatusData for some reason, you can do the same thing with member functions that return Boolean values, expressing the same intent.
HTH!
PS, You might even want to encapsulate the entirety of the nested-ifs into a single concept. Then you'd just have 2 Boolean tests before you return false.
I suspect you might want to take a look at the next level up in the code, the fact its returning a boolean indicates this is being used in a conditional by something else.
That said I do usually like the chain of responsibility pattern for this sort of thing. But I personally wouldn't have it return a boolean, I'd have the responsible object perform an action if it was determined to be responsible for that type of data (i.e. Another level up).
Just an option for you to consider, there isn't a hard and fast rule for this kind of thing.
This doesn't really answer to your question which was about design pattern, but that might still interest you.
You could rewrite your method like that.
First two arrays:
private ApplicationTypePesticide[] typePesticidesNewPurpose
= new ApplicationTypePesticide[]
{
ApplicationTypePesticide.Authorisation,
ApplicationTypePesticide.ProvisionalAuthorisation,
ApplicationTypePesticide.MutualRecognition,
ApplicationTypePesticide.Derogation,
ApplicationTypePesticide.DispensationPreviousAssessment,
ApplicationTypePesticide.ResearchAndDevelopmentPurposesExperimentOrTestProgram,
ApplicationTypePesticide.ResearchAndDevelopmentPurposesExperimentOrTestProgramKnownProduct,
ApplicationTypePesticide.ParallelTradePermit,
ApplicationTypePesticide.Copy
};
private ApplicationTypePesticide[] typePesticidesRenewalPurpose
= new ApplicationTypePesticide[]
{
ApplicationTypePesticide.ReAuthorisation,
ApplicationTypePesticide.ParallelTradePermit,
ApplicationTypePesticide.Copy
};
Then your previous method becomes:
private bool IsMissingAuthorizationStartDate(ApplicationStatusData data)
{
return data.ApplicationStatus == ApplicationStatusType.ApplicationApproved
&& (IsMissingAuthorizationStartDatePart2(data, ApplicationPurpose.New,
ProductStatusType.ApplicationForNewProductReceived, typePesticidesNewPurpose)
|| IsMissingAuthorizationStartDatePart2(data, ApplicationPurpose.Renewal,
ProductStatusType.ProductAuthorised, typePesticidesRenewalPurpose));
}
private bool IsMissingAuthorizationStartDatePart2(ApplicationStatusData data,
ApplicationPurpose purpose, ProductStatusType statusType,
params ApplicationTypePesticide[] typePesticides)
{
return (data.ApplicationPurpose == purpose
&& data.ProductStatus.ProductStatusType == statusType
&& statusType.Any(st => data.ApplicationTypePesticide == st)
&& !data.AuthorizationStartDate.HasValue);
}
Note: you can remove the params keyword if you always call the method like in this example.
You should also think about rename the part2 method.
The situation
I have a method that takes in a POCO. This POCO is like the following
private class SearchCriteria
{
public string name get;set;
public string age get;set;
public string talent get;set;
..
....
}
The method basically has a query to the db , that uses the above criteria.
public void query(SearchCriteria crit)
{
if(crit.name!=null && crit.age!=null && crit.talent !=null)
{
dbContext.Students.Where(c=>c.name ==crit.name && c.age==crit.age...)
}
else if(crit.name !=null && crit.age!=null)
{
}
else if(....
{
}
As you can see there is a definite problem above , where in, in case of large number of criteria, I will have to write a lot of if-elses to drop out specific arguments from the where clause .
The possible solution ?
I am actually new to the lambda expressions world but I believe we must be having a facility which would allow us to do something like below.
dbContext.Students.Where(processCriteria(searchCriteriaPOCO)).
Can you folks lead me to the proper direction ?. Thanks
Get a queryable and then keep adding where clauses to it. That way you only need to test each possible criteria the once and also only generate the number of where clauses that are absolutely needed.
IQueryable<Student> q = dbContext.Students.AsQueryable();
if (crit.name != null)
q = q.Where(c => c.name == crit.name);
if (crit.age != null)
q = q.Where(c => c.age== crit.age);
Let me start by saying that this answer uses the same basic idea as #PhilWright's answer. It just wraps it up in an extension method that applies this pattern for you, and allows you to have a syntax that reads nice.
public static class SearchExtensions
{
public static IQueryable<Student> Query(this SearchCriteria criteria, IQueryable<Student> studentQuery)
{
return studentQuery
.Match(criteria.name, (student) => student.name == criteria.name)
.Match(criteria.age, (student) => student.age == criteria.age)
.Match(criteria.talent, (student) => student.talent == criteria.talent);
// add expressions for other fields if needed.
}
private static IQueryable<Student> Match<T>(
this IQueryable<Student> studentQuery,
T criterionValue,
Expression<Func<Student, bool>> whereClause) where T : class
{
// only use the expression if the criterion value is non-null.
return criterionValue == null ? studentQuery : studentQuery.Where(whereClause);
}
}
You can then use it in your code like this:
var criteria = new SearchCriteria() {
name = "Alex",
talent = "Nosepicking"
};
var results = criteria.Query(dbContext.Students);
Maybe I'm missing something, as the code example is not the clearest I've seen, but for your specific example, I would think the following should be fine:
dbContext.Students.Where(c => (crit.name == null || crit.name == c.name) &&
(crit.age == null || crit.age == c.age) &&
(crit.talent == null || crit.talent == c.talent));
No need to chain a bunch of if statements.
For more complicated scenarios, you might prefer something like PredicateBuilder
You can use a pattern like this:
dbContext.Students.Where(c=>(crit.name == null || c.name ==crit.name) && ...)
A search criterion which is null will give a subexpression which is always true.
I have a test that looks like this:
[Test]
public void Blah()
{
// Arrange
// ...
var thing = new Thing();
mockRouter.Route(Arg.Is<Transition<Thing>>(x => x != null && x.Subject != null && x.Subject.Equals(thing)));
// Act
var result = handler.Handle(thing);
// Assert
mockRouter.Received(1).Route(Arg.Is<Transition<Thing>>(x => x != null && x.Subject != null && x.Subject.Equals(thing)));
}
I would like to cache up the Arg definition in a local variable so I can reuse it in the assert. The point is to reduce the amount of code in the test and make it read a bit more fluidly.
[Test]
public void Blah()
{
// Arrange
var thing = new Thing();
var transitionForThing = Arg.Is<Transition<Thing>>(x => x != null && x.Subject != null && x.Subject.Equals(thing));
mockRouter.Route(transitionForThing);
// ...
// Act
var result = handler.Handle(thing);
// Assert
mockRouter.Received(1).Route(transitionForThing);
}
This does not seem to work, as the value of transitionForThing is null, and so the assertion fails saying that Received(null) was not called. Is there a way to do this or something similar, or am I stuck with this syntax?
Arg.Is has a parameter of type
Expression<Predicate<T>>
, so you can define it to reuse
Expression<Predicate<Transition<Thing>>> predicate =
x => x != null && x.Subject != null && x.Subject.Equals(thing));
and use it as
mockRouter.Route(predicate);
But i really don't understand your situation: you usually mock classes that return some result that you need. I think in your case you only need to check that the method of the mocked class has been called, you don't need to define a mock for the action.
The value returned by Arg.Is(...) and other Arg methods is of relatively little importance. The important bit is the invocation of the method itself.
Every time Arg.Is(...) is called NSubstitute takes note that you tried to specify an argument, and uses that information to work out the details of the call you are specifying. If you cache the value (which will just be default(T)), NSubstitute will not know you want to match the same argument.
I can explain this more if you are interested, but the important thing to note is you need to call Arg.Is(...) every time you specify a call (and in the correct order expected for the call).
To reuse matcher logic I'd extract the predicate into a new method (as DaniCE suggested), or create a method that calls Arg.Is and use it with caution.
[Test]
public void Blah() {
var thing = new Thing();
mockRouter.Route(Arg.Is<Transition<Thing>>(x => HasSubject(x, thing)));
// ...
var result = handler.Handle(thing);
// ...
mockRouter.Received(1).Route(Arg.Is<Transition<Thing>>(x => HasSubject(x, thing)));
}
private bool HasSubject(Transition<Thing> x, Thing thing) {
return x != null && x.Subject != null && x.Subject.Equals(thing));
}
//or...
[Test]
public void Blah2() {
var thing = new Thing();
mockRouter.Route(ArgWith(thing));
// ...
var result = handler.Handle(thing);
// ...
mockRouter.Received(1).Route(ArgWith(thing));
}
private Transition<Thing> ArgWith(Thing thing) {
return Arg.Is<Transition<Thing>>(x => x != null && x.Subject != null && x.Subject.Equals(thing));
}
So I'm trying to use FindAll to return a list of objects that match. It works great when I only use one condition, for example
patientstatus = statuslist.FindAll(delegate(StatusReader.onestatus p1)
{
return p1.WL_ID == patlist[i].wl_id;
});
But I would like to use multiple conditions, some of which contain if statements and I can't figure out how. It seems like the format needs to have a return statement, and the example from Microsoft (http://msdn.microsoft.com/en-us/library/fh1w7y8z.aspx) only uses one condition.
I could either have multiple FindAll methods for each condition, or just make a loop that scans through all the values myself, but there's got to be an obvious thing I'm missing, right?
I'm not quite sure what "if loops" are, but you can always just stitch them together:
patientstatus = statuslist.FindAll(delegate(StatusReader.onestatus p1)
{
if(p1.WL_ID != patlist[i].wl_id)
return false;
if(otherStuff != 5)
return false;
for(var x in p1.stuff)
if(x == 7)
return false;
return true;
});
Try the following:
var patientStatus = statusList.Where(p => p
{
// Put in logic here as you need
return p.WL_ID == patlist[i].wl_id || p.YourSecondProperty == WhateverYouWantToCheck;
}
You can think about something like
public abstract class Condition
{
public abstract bool Sutisfied(StatusReader.onestatus status);
}
public class Condition1 : Condition
{
public override bool Sutisfied(StatusReader.onestatus status) {
//check for something and return
}
}
public class Condition2 : Condition
{
public override bool Sutisfied(StatusReader.onestatus status) {
//check for something and return
}
}
After can have a list of conditions, like
List<Condition> conditions =
new List<Condition>{new Conditon1(), new Condition2()}
and after this list use inside
patientstatus = statuslist.FindAll(delegate(StatusReader.onestatus status)
{
return conditions.TrueForAll(c=>c.Sutisfied(status));
});
Your delegate simply needs to return true for a match to your conditions and false for a non-match to your conditions. It doesn't have to be a single line return statement. You can create boolean values, have if statements, for loops, and anything else you want in your delegate - so long as it returns true or false along all code paths.
So you can do as many if statements or loops as you want.
If you really want to maintain it as one line, you can do something like the following...
return (condition1 == condition1) || (condition2 == condition2) || (condition3 == condition3);