I have an example of some code that I see often in websites that I'd like to improve and would appreciate some help. Often I see 5-10 nested if-statements in a page_load method which aim to eliminate invalid user input, but this looks ugly and is hard to read and maintain.
How would you recommend cleaning up the following code example? The main thing I'm trying to eliminate is the nested if statements.
string userid = Request.QueryString["userid"];
if (userid != ""){
user = new user(userid);
if (user != null){
if (user.hasAccess){
//etc.
}
else{
denyAccess(INVALID_ACCESS);
}
}
else{
denyAccess(INVALID_USER);
}
}
else{
denyAccess(INVALID_PARAMETER);
}
As you can see, this gets quite messy very quickly! Are there any patterns or practices that I should be following in this case?
By using Guard Clauses sir
string userid = Reuest.QueryString["userid"];
if(userid==null)
return denyAccess(INVALID_PARAMETER);
user = new user(userid);
if(user==null)
return denyAccess(INVALID_USER);
if (!user.hasAccess)
return denyAccess(INVALID_ACCESS);
//do stuff
PS. use either return or throw an error
You can clean up the nesting a bit by negating the conditions and write an if-else chain:
string userid = Reuest.QueryString["userid"];
if (userid == "") {
denyAccess(INVALID_PARAMETER);
} else if (null == (user = new user(userid))){
denyAccess(INVALID_USER);
} else if (!user.hasAccess){
denyAccess(INVALID_ACCESS);
} else {
//etc.
}
Better to split it into multiple methods(functions) .It will be easy to understand.If some new person reads the code he/she understands the logic just by reading the method name itself(Note: Method name should express what test it does).Sample code :
string userid = Request.QueryString["userid"];
if(isValidParameter(userId)){
User user=new User(userId);
if(isValidUser(user)&&isUserHasAccess(user)){
//Do whatever you want
}
}
private boolean isUserHasAccess(User user){
if (user.hasAccess){
return true;
}else{
denyAccess(INVALID_ACCESS);
return false;
}
}
private boolean isValidUser(User user){
if(user !=null){
return true;
}else{
denyAccess(INVALID_USER);
return false;
}
}
private boolean isValidParameter(String userId){
if(userid !=""){
return true;
}else{
denyAccess(INVALID_PARAMETER);
return false;
}
}
Related
I have a TADOConnection pointing to a MySQL 8.0 instance. The connection is tested and it works. Following this example on how to use prepared statement, I'm having an error and I have no idea why.
The following code works fine, it will return true from the very last statement. No errors, no warnings.
AnsiString sqlQuery = "SELECT e.name FROM employee e WHERE e.id = 1;";
if (!_query->Connection->Connected) {
try {
_query->Connection->Connected = true;
} catch (EADOError& e) {
return false;
}
}
_query->SQL->Clear();
_query->SQL->Add(sqlQuery);
_query->Prepared = true;
try {
_query->Active = true;
if (_query->RecordCount == 0) {
return false;
}
} catch (EADOError& e) {
return false;
}
return true;
However, the following code fails executing _query->SQL->Add(sqlQuery); with this error:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
AnsiString sqlQuery = "SELECT e.name FROM employee e WHERE e.id = :id;";
if (!_query->Connection->Connected) {
try {
_query->Connection->Connected = true;
} catch (EADOError& e) {
return false;
}
}
_query->SQL->Clear();
_query->SQL->Add(sqlQuery); // <---- EOleException here
_query->Parameters->ParamByName("id")->Value = id;
_query->Prepared = true;
try {
_query->Active = true;
if (_query->RecordCount == 0) {
return false;
}
} catch (EADOError& e) {
return false;
}
return true;
Everywhere I find examples, all of them use :paramName to specify parameters. What am I missing?
Update 1
I have tried changing the code like this :
_query->SQL->Clear();
TParameter * param = _query->Parameters->AddParameter();
param->Name = "id";
param->Value = 1;
_query->SQL->Add(sqlQuery); // <---- EOleException still here
Some forum post suggests to switch the Advanced Compiler option "Register Variables" to "None", but this is already the setting of my project, and the exception is still thrown.
Update 2
I can ignore the error, and everything gets executed just fine, however it fails whenever I perform a step-by-step execution. Of course, I can still put a breakpoint after, and jump right over the faulty line, but it's still annoying and does not explain why there is this error there in the first place.
The exception is on setting the SQL string - which tells you that it's wrong. As per #RogerCigol's comment, you should NOT have the ; at the end of your SQL string.
Kudos to Roger for that.
If you want to access parameters, you MUST set the SQL string first, it will be parsed to identify the parameters. The parameters will not exist until the string is parsed, or you manually create them (which is pointless as they would be recreated on parsing the string).
You can also access the parameters as an ordered index, and I have always been able to use ? as an anonymous parameter with MySQL.
I have a doubt with the solution of this question which is stated below -
Given an arbitrary ransom note string and another string containing letters from all the magazines, write a function that will return true if the ransom note can be constructed from the magazines ; otherwise, it will return false.
Each letter in the magazine string can only be used once in your ransom note.
Strings["aa", "ab"] should return false and strings["aa", "aab"] should return true according to question.
Here is the code which I have attempted in the first place and I'm not getting a required output as mentioned above.
unordered_map<char,int>umap;
for(char m:magazine)
{
umap[m]++;
}
for(char r:ransomNote)
{
if(umap.count(r)<=1)
{
return false;
}
else{
umap[r]--;
}
}
return true;
}
In the above code, I have used umap.count(r)<=1 to return false if there is no key present.
For the strings ["aa","aab"], it is returning true but for strings ["aa","ab"], it is also returning true but it should return false.
Then I used another way to solve this problem by using just umap[r]<=0 in the place of umap.count(r)<=1 and it is working just fine and else all code is same.
bool canConstruct(string ransomNote, string magazine) {
unordered_map<char,int>umap;
for(char m:magazine)
{
umap[m]++;
}
for(char r:ransomNote)
{
if(umap[r]<=0)
{
return false;
}
else{
umap[r]--;
}
}
return true;
}
I'm not able to get what i'm missing in the if condition of first code. Can anyone help me to state what I'm doing wrong in first code. Any help is appreciated.
unordered_map::count returns the number of items with specified key.
As you don't use multi_map version, you only have 0 or 1.
Associated value doesn't change presence of key in map.
To use count, you should remove key when value reaches 0:
for (char r : ransomNote) {
if (umap.count(r) == 0) {
return false;
} else {
if (--umap[r] == 0) {
umap.erase(r);
}
}
}
return true;
Everytime I run the my function SearchByID it won't return the necessary boolean operators that I needed. The method reads to the Employee.txt files and read files one after another. What I did is I created a String array to store the splitted strings, and doing the String.equalsIgnorCase() method to check if the corresponding matches w/ the data on the file. Here is the code for the method
Code: SearchByID
public static boolean SearchByID(String ID){
boolean bool = false;
int idLoc = 3;
try(BufferedReader bufr = new BufferedReader(new FileReader(EMPLOYEE_TXT))){
String line = bufr.readLine();
/*Split the records into an array*/
String[] lines;
while(line !=null){
//do the macthing of data here
lines = line.split(";");
if(lines[idLoc].equalsIgnoreCase(ID)){
bool = true;
break;
}else{
bool = false;
break;
}
}
bufr.close();
}catch(Exception ex){
ex.printStackTrace();
}
return bool;
}
Here is the implementation of the method SearchByID();
System.out.print("Search user by ID:");
String strID = sID.nextLine();
if(IOLibraries.SearchByID(strID)){
System.out.println("A match has been found");
}else{
System.out.println("No match found");
}
Content of the Employee.txt
kadi,bens;male;baliwasan grande;88-11;99111;arg11#gmail.com;400.0
doe,john;male;11311 asdd;99811;9911331;asdf#.sdfcom;500.0
What I really need to do is I need to read all the data on the file after that it should return the correct boolean values in order search for all the users on the Employee.txt file.
I could not retrieve if I search the values below the first entries. For example if i search for id 88-11 I could retrieve the data properly, however if I search below the first entry such as 99811 it would return false or "No match found" even if it is in the Employee.txt files.
The problem is you will always break out from the loop after reading the first line.
while(line !=null){
//do the macthing of data here
lines = line.split(";");
if(lines[idLoc].equalsIgnoreCase(ID)){
bool = true;
break;
}else{
bool = false;
break;
}
}
Note the else block. If first line does not match the ID, it will go into the else block, which declare that it is not found, and breaking out.
What you should do is
initialize bool (or better call it found) as false before the loop (for which you have done already)
Only break out of loop if you found the matching line
i.e. change the loop to something like
while(line !=null){
lines = line.split(";");
if(lines[idLoc].equalsIgnoreCase(id)){
found = true;
break;
}
}
This might be a non-sense question, but i'm kind of stuck so I was wondering if someone can help. I have the following code:
bool while_condition=false;
do{
if(/*condition*/){
//code
}
else if(/*condition*/){
//code
}
else if(/*condition*/){
//code
}
...//some more else if
else{
//code
}
check_for_do_while_loop(while_condition, /*other parameters*/);
}while(while_condition);
the various if and else if exclude with each other but each have other if inside; if a certain condition is met (which can't be specified in a single if statement), then the code return a value and the do while loop is ended. But if, after entering a single else if, the conditions inside aren't met the code exit without actually doing nothing, and the while loop restart the whole.
I want the program to remember where he entered and avoid that part of the code, i.e. to avoid that specific else if he entered without any result, so he can try entering another else if. I thought about associating a boolean to the statements but I'm not quite sure on how to do it. Is there a way which allows me not to modify the code structure too much?
To give an idea of one way of approaching this that avoid loads of variables, here is an outline of how you might data-drive a solution.
class TestItem
{
public:
typedef bool (*TestFuncDef)(const state_type& state_to_test, std::shared_ptr<result_type>& result_ptr);
TestItem(TestFuncDef test_fn_parm)
{
test_fn = test_fn_parm;
already_invoked = false;
}
bool Invoke(const state_type& state_to_test, std::shared_ptr<result_type>& result_ptr)
{
already_invoked = true;
return test_fn(state_to_test, result_ptr);
}
bool AlreadyInvoked() const {return already_invoked; }
private:
TestFuncDef test_fn;
bool already_invoked;
};
std::shared_ptr<result_type> RunTest(std::list<TestItem>& test_item_list, state_type& state_to_test)
{
for(;;) {
bool made_a_test = false;
for (TestItem& item : test_item_list) {
std::shared_ptr<result_type> result_ptr;
if (!item.AlreadyInvoked()) {
made_a_test = true;
if (item.Invoke(state_to_test, result_ptr)) {
return result_ptr;
}
else
continue;
}
}
if (!made_a_test)
throw appropriate_exception("No conditions were matched");
}
}
This is not supposed to be a full solution to your problem but suggests another way of approaching it.
The important step not documented here is to build up the std::list of TestItems to be passed to RunTest. Code to do so might look like this
std::list<TestItem> test_item_list;
test_item_list.push_back(TestItem(ConditionFn1));
test_item_list.push_back(TestItem(ConditionFn2));
The definition of ConditionFn1 might look something like
bool ConditionFn1(const state_type& state_to_test, std::shared_ptr<result_type>& result_ptr)
{
// Do some work
if (....)
return false;
else {
result_ptr.reset(new result_type(some_args));
return true;
}
}
My program waits for user input, and when appropriate, will process it. I need to check the user input to make sure it fulfils certain criteria, and if it doesn't fulfil all of those criteria it will be rejected.
Pseudo-code is something like:
if (fulfills_condition_1)
{
if (fulfills_condition_2)
{
if (fulfills_condition_3)
{
/*process message*/
}
else
cout << error_message_3; //where error_message_1 is a string detailing error
}
else
cout << error_message_2; //where error_message_2 is a string detailing error
}
else
cout << error_message_1; //where error_message_3 is a string detailing error
There is the possibility that the number of these conditions could increase, and I was wondering if there was a neater way to represent this using a switch or something like that instead of lots of cascading if statements.
I know there is the possibility of using
if (fulfills_condition_1 && fulfills_condition_2 && fulfills_condition_3)
/*process message*/
else
error_message; //"this message is not formatted properly"
but this is less useful than the first, and does not say where the issue is.
The conditions can roughly be arranged in increasing importance i.e. checking for condition_1 is more important than checking for condition_3, so the if statements do work - but is there a better way in general for doing this?
How about
if (!fulfills_condition_1) throw BadInput(error_message_1);
if (!fulfills_condition_2) throw BadInput(error_message_2);
if (!fulfills_condition_3) throw BadInput(error_message_3);
/* process message */
Then your exception handler can report the error message, and retry or abort as appropriate.
If what bothers you are the cascading ifs, you could go for one of the following:
Using a boolean:
bool is_valid = true;
string error = "";
if (!condition_one) {
error = "my error";
is_valid = false;
}
if (is_valid && !condition_two) {
...
}
...
if (!is_valid) {
cout << error;
} else {
// Do something with valid input
}
Using exceptions:
try {
if (!condition_one) {
throw runtime_error("my error");
}
if (!condition_two) {
...
}
...
} catch (...) {
// Handle your exception here
}
I suggest you can use "early return" technique:
if (!fulfills_condition_1)
// error msg here.
return;
// fulfills_condition1 holds here.
if (!fulfills_condition_2)
// error msg here.
return;
// Both conditon1 and condition2 hold here.
if (!fulfills_condition_3)
// error msg here.
return.
If this was going to be reused in a few places, I would make a DSL:
Validator inputType1Validator =
Validator.should(fulfill_condition_1, error_message_1)
.and(fulfill_condition_2, error_message_2)
.and(fulfill_condition_3, error_message_3)
inputType1Validator.check(input);