I'm tracing some code, and a list is sent to the below, to remove certain items from the list.
Is this the proper way to use the goto? Is it even necessary? Wouldn't you just edit the second if to be an else if, and continue processing the list without the need for a goto? (This is the first time I've ever seen goto outside of BASIC.)
public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
if (src == null)
return null;
checkAB01:
for (int i = 0; i < src.Count; i++)
{
ClientEntity info = src[i];
if (info.ProductNumber != null && info.ProductNumber.ToLower().Trim().Length > 0
&&
info.CancelledByReliantSyncAB01 != null && info.CancelledByReliantSyncAB01.Value == true
)
{
src.Remove(info);
goto checkAB01;
}
if ((info.PartnerContract == null || info.PartnerContract.Trim().Length == 0)
&&
(info.ProductNumber == null || info.ProductNumber.Trim().Length == 0))
{
src.Remove(info);
goto checkAB01;
}
}
return src;
}
How about LINQ?
public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
if (src == null)
return null;
return (from info in src.AsEnumerable<ClientEntity>()
where !(!String.IsNullOrWhiteSpace(info.ProductNumber) &&
info.CancelledByReliantSyncAB01 == (bool?)true)
where !(String.IsNullOrWhitespace(info.PartnerContract) &&
String.IsNullOrWhiteSpace(info.ProductNumber))
select info).ToList();
}
No, this isn't a proper way to use goto, it's just a substitute for someone who doesn't know how to properly remove items from a list. (Iterate backwards to prevent skipping elements)
public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
if (src == null)
return null;
for (int i = src.Count - 1; i >= 0; i--)
{
ClientEntity info = src[i];
if (info.ProductNumber != null && info.ProductNumber.ToLower().Trim().Length > 0
&&
info.CancelledByReliantSyncAB01 != null && info.CancelledByReliantSyncAB01.Value == true
)
{
src.RemoveAt(i);
}
if ((info.PartnerContract == null || info.PartnerContract.Trim().Length == 0)
&&
(info.ProductNumber == null || info.ProductNumber.Trim().Length == 0))
{
src.RemoveAt(i);
}
}
return src;
}
I think whoever wrote this code did not know how to remove items from the iterated collection. The reason for those gotos was that once an item is deleted, the collection becomes smaller which can cause iteration errors.
A better day to do this is to do a reverse for loop. This way you do not have to reiterate through the whole list after a deletion. The code below will work just fine.
for (int i = src.Count - 1; i >= 0; i--) {
src.Remove(src[i]);
}
As others have said, this is a poor usage of goto (which should rarely, if ever, be used)
Overall though, the implementation is terribly inefficient. Looks like it loops through from 0..N until it removes something, then starts again from 0..N (now 1 less) until it removes something, and so on. Even worse, the Remove call again goes from 0..N looking for that item to remove.
If it finds nothing to remove, it returns. Better to just do a reverse for loop removing entries with RemoveAt then returning.
public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
if (src == null)
return null;
for (int i = src.Count - 1; i >= 0; i--)
{
ClientEntity info = src[i];
if (info.ProductNumber != null && info.ProductNumber.ToLower().Trim().Length > 0
&&
info.CancelledByReliantSyncAB01 != null && info.CancelledByReliantSyncAB01.Value == true)
{
src.RemoveAt(i);
}
else if ((info.PartnerContract == null || info.PartnerContract.Trim().Length == 0)
&&
(info.ProductNumber == null || info.ProductNumber.Trim().Length == 0))
{
src.RemoveAt(i);
}
}
return src;
}
Also, I added an elseif there: seems dangerous to do another if check that could potentially be true and try to re-remove the same item (especially after changing the indices).
EDIT: If we're talking about readable usable code, I'd move out the checks to a separate method anyway:
public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
if (src == null)
return null;
for (int i = src.Count - 1; i >= 0; i--)
{
if (ShouldClientNotSendBack(src[i]))
src.RemoveAt(i);
}
return src;
}
private static bool ShouldClientNotSendBack(ClientEntity info)
{
if (!String.IsNullOrWhiteSpace(info.ProductNumber) && info.CancelledByReliantSyncAB01 == true)
{
return true;
}
if (!String.IsNullOrWhiteSpace(info.PartnerContract))
{
return true;
}
return false;
}
Might even consider tweaking that ShouldClientNotSendBack method and/or name (perhaps even move the two sets of if checks to individual methods with clear names), but this I think is a significant improvement overall.
EDITx2: In fact, I would strongly consider usage of the method. The method is clearly returning an IList<ClientEntity> while taking in an input collection, which typically communicates to developers that this is creating a new list when in fact it's actually mutating the existing list and returning the same list instance. Either have it return a new list (thus you should change the loop code to add to a new list instead of removing from the existing) or remove the return type so it's more apparent that it's mutating the passed list argument.
As I stated in my comment, there is no "proper" way to use goto in C#. The keyword is, by its very definition, a kludge; it's a throwback to C/C++, which included it as a "just in case", should a developer want to translate line-by-line a program in ASM or BASIC or other language without defined code blocks, which hide the "jumps" used to get into and between them. Any algorithm that uses it can be refactored to not have to do so, and the resulting algorithm will be more readable.
In this case:
public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
if (src == null)
return null;
for (int i = src.Count-1; i>=0; i--)
{
ClientEntity info = src[i];
if (info.ProductNumber != null && info.ProductNumber.ToLower().Trim().Length > 0
&&
info.CancelledByReliantSyncAB01 != null && info.CancelledByReliantSyncAB01.Value == true
)
{
src.Remove(info);
continue;
}
if ((info.PartnerContract == null || info.PartnerContract.Trim().Length == 0)
&&
(info.ProductNumber == null || info.ProductNumber.Trim().Length == 0))
{
src.Remove(info);
continue;
}
}
return src;
}
As Chris Sinclair's answer shows, because of the "either/or" implicit structure of the conditionals in the loop, the continue statements aren't necessary, but I like them because they show the coder that nothing from that point to the end of the loop will be run, without them having to read the rest of it to determine that.
If you wanted to, you could run through the list front to back, and if an item is removed, decrement i before continuing so that the loop will maintain its current position in the list. Some may say not to do it this way because the manipulation of the counter makes it harder to understand the algorithm (and because determining the count of the list on each iteration is slightly slower), but it's still far better in both performance and readability than the goto.
Related
I need to execute an else statement from a if, and another if inside it.
if (!BoxA_IsNull && !BoxB_IsNull && !BoxC_IsNull && !BoxD_IsNull) //Scenario 1
{
if (BoxA == BoxB && BoxC == BoxD) //Scenario 2
{
//Do something
}
}
else
{
// Do something else if
// 1) Scenario 1 hits but not scenario 2
// 2) Scenario 1 does not hit
}
May I know how can I go to else statement regardless if scenario 1 or scenario 2 hits?
Edit: Apologies on scenario confusion. Have edited as above in else statement
At the end I went with the following solution of
if ((!BoxA_IsNull && !BoxB_IsNull && !BoxC_IsNull && !BoxD_IsNull) && (BoxA == BoxB && BoxC == BoxD))
{
//do something
}
Reason is because during if, it will hit 2nd comparison check if 1st null check fails. The purpose of my 1st null check is to prevent null exception during 2nd comparison check.
Store the conditions in boolean variables. Then you can reuse them.
bool nullCondition = !BoxA_IsNull && !BoxB_IsNull && !BoxC_IsNull && !BoxD_IsNull;
bool equalityCondition = BoxA == BoxB && BoxC == BoxD;
if (nullCondition && equalityCondition)
{
// Both conditions are true
}
else
{
// Any of equalitycondition or nullcondition is false
}
You could store the scenarios in two boolean variables, which makes the check more easily:
bool scenario1 = !BoxA_IsNull && !BoxB_IsNull && !BoxC_IsNull && !BoxD_IsNull;
bool scenario2 = BoxA == BoxB && BoxC == BoxD
if (scenario1)
{
if (scenario2)
{
//do something
}
}
if((scenario1 && !scenario2) || !scenario1)
{
//do something else if either Scenario 1 or 2 hits.
}
Depending on what you are doing exactly, you could also give the variables more expressive names.
I'm not sure I'm understanding you question correctly; the logic you seem to want with your example is pretty simple:
if (!BoxA_IsNull && !BoxB_IsNull && !BoxC_IsNull && !BoxD_IsNull)
{
if (BoxA == BoxB && BoxC == BoxD)
{
//Scenario 1 & 2
}
else
{
//Scenario 1 hits but not scenario 2
}
}
else
{
//Scenario 1 does not hit
}
I have Client group logo and Client site logo. And want to assign Client site logo a value based on certain conditions.
This is my code in ClientController.cs :
if (site.ImageURL != null && site.ImageURL != "" && clientGroupImage != "/Content/Images/ClientLogoDefault.svg"
&& site.ImageURL != "/Content/Images/ClientSiteLogoDefault.svg" || site.ImageURL != null
&& site.ImageURL != "" && clientGroupImage == "/Content/Images/ClientLogoDefault.svg"
&& site.ImageURL != "/Content/Images/ClientSiteLogoDefault.svg")
{
model.SiteLogoURL = site.ImageURL;
}
else if (site.ImageURL == "/Content/Images/ClientSiteLogoDefault.svg"
&& clientGroupImage != "/Content/Images/ClientLogoDefault.svg" || site.ImageURL == ""
&& clientGroupImage != "/Content/Images/ClientLogoDefault.svg")
{
model.SiteLogoURL = clientGroupImage;
}
else
{
model.SiteLogoURL = "/Content/Images/ClientSiteLogoDefault.svg";
}
So is there a way to write this code using less "&&" and "||" operators?
There are a few ways you can do this;
By writing boolean function for complex conditions, separate complex conditions from code to improve readability and ease of use. You can also re-use these functions for other similar scenarios.
In your case, extract out string literals into variable or const strings. They will be easier to manage easier to read/use. Like Zaven Suggested.
Nesting conditions when for cases there is common condition. Nesting is similar to if-then lingo.
bool client = clientGroupImage == "/Content/Images/ClientLogoDefault.svg";
bool site = site.ImageURL == "/Content/Images/ClientSiteLogoDefault.svg";
if (!string.IsNullOrEmpty(site.ImageURL) && (!client && !site || client && !site)
{
model.SiteLogoURL = site.ImageURL;
}
else if (!client && (site || site.ImageURL == "")
{
model.SiteLogoURL = clientGroupImage;
}
else
{
model.SiteLogoURL = "/Content/Images/ClientSiteLogoDefault.svg";
}
Your conditional statements are not entirely clear, but in general you could treat compounded conditional statements (with AND and OR) a bit like math operators.
For example, in math you can do this: A*B + A*C = A*(B+C)
Now let treat A,B,C as simple conditions and assume * is AND and + is OR.
So if ((A && B) OR (A && C)) can also be if (A && (B OR C))
For your specific case, I would need some clarifications about the first if statement, but I think you can do something like:
if (!string.IsNullOrEmpty(site.ImageURL) && site.ImageURL != "/Content/Images/ClientSiteLogoDefault.svg" &&
(clientGroupImage != "/Content/Images/ClientLogoDefault.svg" || clientGroupImage == "/Content/Images/ClientLogoDefault.svg"))
Seeing as the only difference is clientGroupImage condition, which if you notice will cover all cases, so you can drop this entirely.
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.
I am somewhat of a beginner programmer. What I am trying to do here is to check that if there is a time, if it is selected, and if that time is equivalent to the other. If that is all true then I want to skip the block of code under it. Here is the code example:
if (currentGVR.Round_Start_Time)
{
if (tr.StartLunchDateTime != null && currentGVR.Round_Start_Lunch && roundedStart == roundedStartL)
// skip
else
{
key = tr.TransactionID;
TransactionRecords[key]["Start_DateTime"] = roundedStart;
}
}
I thought about using an OR operator, but I can see where an error would occur if there was no time to compare to. Using the AND operator avoids this dilemma here.
So the overall question is, is it proper coding to negate all of the conditions to get the correct result, e.g. if (!( cond's )), and also, would this be the best way to check if there is a value to compare with before actually comparing it in C# and otherwise? The times can be null (or do not exist) in some records. Any recommendations?
I'd negate all those conditions and switch the && to || so it's more quickly evident under what conditions the code will (or will not) execute.
Plus (in my experience), you don't typically see an empty if block with all the code under the else.
if (tr.StartLunchDateTime == null || !currentGVR.Round_Start_Lunch || roundedStart != roundedStartL)
{
key = tr.TransactionID;
TransactionRecords[key]["Start_DateTime"] = roundedStart;
}
The statement
if (tr.StartLunchDateTime != null && currentGVR.Round_Start_Lunch && roundedStart == roundedStartL){
// skip
}
else
{
key = tr.TransactionID;
TransactionRecords[key]["Start_DateTime"] = roundedStart;
}
is equivalent to
if (!(tr.StartLunchDateTime != null && currentGVR.Round_Start_Lunch && roundedStart == roundedStartL))
{
key = tr.TransactionID;
TransactionRecords[key]["Start_DateTime"] = roundedStart;
}
else {
// skip
}
This can be further simplified because
!(tr.StartLunchDateTime != null &&
currentGVR.Round_Start_Lunch &&
roundedStart == roundedStartL)
Is the same as
(!(tr.StartLunchDateTime != null) ||
!(currentGVR.Round_Start_Lunch) ||
!(roundedStart == roundedStartL))
or
(tr.StartLunchDateTime == null ||
!currentGVR.Round_Start_Lunch ||
roundedStart != roundedStartL)
See DeMorgan's Laws.
if (someLongCondition)
{ }
else
{
doStuff();
}
is equivalent to this:
if (!someLongCondition)
{
doStuff();
}
So yeah, you can just negate your whole condition:
if (!(tr.StartLunchDateTime != null && currentGVR.Round_Start_Lunch && roundedStart == roundedStartL))
{ … }
But you can also pull the negation in (applying De Morgan's laws) and write it like this:
if (tr.StartLunchDateTime == null || !currentGVR.Round_Start_Lunch || roundedStart != roundedStartL)
{ … }
All these are equivalent so choose whatever makes the condition more clear (actually, consider storing it in a separate variable which you give a descriptive name).
I'm working right now to build LINQ up to the side where it needs to retrieve some information from the user about how many applications as you have got to be friends. - user exists in tablen.
venner Numberoffriends = db.venners.Where(UseridFriends => UseridFriends.To == 1 && UseridFriends.Godkendt == 0).Count();
if(Numberoffriends != null)
{
//true
}
it is such that it now makes mistakes here
db.venners.Where(UseridFriends => UseridFriends.To == 1 && UseridFriends.Godkendt == 0).Count();
ERROR ARE: The type 'int' can not be implicitly converted to 'LinqData.venner'
The error is because the return type of the Count() extension method is int, and you are trying to assign the return value to a LinqData.venner.
There is no implicit conversion from int to LinqData.venner, so that is the source of your error.
You can confirm this by refactoring your code into the following equivalent code:
int count = db.venners.Where(UseridFriends => UseridFriends.To == 1 && UseridFriends.Godkendt == 0).Count();
venner Numberoffriends = count;
if ( Numberoffriends != null )
{
//true
}
which will transfer your compilation error to the
venner Numberoffriends = count;
line.
It seems from your code that instead of having a count (using the Count() method), you want something like FirstOrDefault() or ToList(). This will enable you to do something with the venner object(s) you get.
I think the following would build, but I'm not sure about your intention and hence if it's what you want:
List<venner> venners = db.venners
.Where(UseridFriends => UseridFriends.To == 1 && UseridFriends.Godkendt == 0)
.ToList();
if ( venners.Count != 0 )
{
//true
// do something with venners here
}
What are you trying to do with your linq?