Why am I getting a format exception in this C# code? - c#

I am working on a Windows Form application. I am parsing an XML file and doing some queries. For example, in this case I am trying to find all users weighing between 55 and 100. For some reason, when I run this code, I get a format exception unhandled. Why am I getting a format exception. I have indicated the breakpoint where the exception occurs. I think the problem is a syntactical error.
Thanks for your help.
private bool UserWeighsBetween55and100(IEnumerable<XElement> paramsList) {
bool result = false;
foreach (XElement parameter in paramsList) {
if (parameter.Attribute("name").Value == "Weight") {
--->HERE if ((Int32.Parse(parameter.Attribute("value").Value) > 55) &&
(Int32.Parse(parameter.Attribute("value").Value) < 100)){
return true;
}
}
}
return result;
}

Convert your value once instead of converting same value two time.
Try to do like this.
int iValue = 0;
if (Int.TryParse(parameter.Attribute("value").Value, out iValue)) //If the value converted
{
if (iValue > 55 && iValue < 100)
{
return true;
}
}
else //Failed to convert value into int datatype
{
//Code here if conversion faild
}
if the parameter.Attribute("value").Value is containing non-numeric value then it wont convert in int datatype.

Instead of using the "Parse" method, use the tryParse.
In your case, it would look like :
foreach (XElement parameter in paramsList) {
if (parameter.Attribute("name").Value == "Weight") {
int value;
if(!Int32.TryParse(parameter.Attribute("value").Value, out value)){
//Not a number, handle this case
}
if ((value > 55) && (value < 100)){
return true;
}
return result;
}

I will be answering my question because I found out my mistake and I hope it would help everybody reading this post.
The problem with using Int32.Parse() was that while I was parsing the XML file, I didn't pay attention to the values of type double.
The fix for this code would be as follows:
private bool UserWeighsBetween55and100(IEnumerable<XElement> paramsList) {
bool result = false;
foreach (XElement parameter in paramsList) {
if (parameter.Attribute("name").Value == "Weight") {
if ((parameter.Attribute("value").Value)!=null) {
if ((Convert.ToDouble(parameter.Attribute("value").Value) > 55) && (Convert.ToDouble(parameter.Attribute("value").Value) < 100)) {
return true;
}
}
}
}
return result;
}

Related

Throw an exception or just return a string?

Say I have this function which checks for user details
//check valid user's details.
private bool checkUserDatails(String nickname, String groupId)
{
//check nickname
if ((nickname == null || nickname.Trim().Equals("")))
{
return false;
}
//check groupId
if (groupId == null)
return false;
//convert to int
int id;
try
{
id = int.Parse(groupId);
}
catch (Exception) { return false; }
//check id
if (id < 0 | id > 100)
return false;
return true;
}
It works great, but the caller function doesn't know why the function returned false if it did. My initial thought was to create my own exceptions such as IncorrectUsernameException etc. and throw them. I could also make the return value string and just return "Incorrect username".
What's the correct C# approach to this?
Following Microsoft conventions (in some places, at least), this should look like:
private void EnsureValidDetails(string nickname, string groupId)
{
if (string.IsNullOrWhiteSpace(nickname))
{
throw new ArgumentNullException(nameof(nickname));
}
else if (string.IsNullOrEmpty(groupId))
{
throw new ArgumentNullException(nameof(groupId));
}
int parsedGroupId;
if (!int.TryParse(groupId, out parsedGroupId))
{
// or some better wording
throw new ArgumentException("GroupId is not a valid number.");
}
if (parsedGroupId < 0 || parsedGroupId > 100)
{
throw new ArgumentOutOfRangeException("GroupId must be between 0 and 100.");
}
}
Notice though, that this method is doing more than it should be doing. groupId should be an int parameter, and the method should only check for the value to be inside the valid range:
private void EnsureValidDetails(string nickname, int groupId)
{
if (string.IsNullOrWhiteSpace(nickname))
{
throw new ArgumentNullException(nameof(nickname));
}
else if (groupId < 0 || groupId > 100)
{
throw new ArgumentOutOfRangeException("GroupId must be between 0 and 100.");
}
}
Yet, this might not be the best way to actually validate this kind of stuff. It certainly works as a generic, framework-independent way, but some .NET frameworks (WPF, WCF, WinForms, ASP.NET) provide built-in ways for doing this.
You shouldn't throw an exception, as it will probably happen quite often that the value false is returned. This would cause a pretty big performance decrease. Instead you could for example use an enum, with values like correct, invalid_nickname, invalid_id and so on.
enum CheckUserDetailsResult { correct, invalid_nickname, invalid_id }
Alternatively you could provide the message via the out reference like that:
private bool checkUserDetails (String nickname, String groupId, out String message)
{
if (String.IsNullOrEmpty (nickname))
{
message = "Invalid nickname!";
return false;
}
//and so on
}

Issues with > and < in C#

I have an issue with a small piece of code I've made.
For the code I have to make a small check. When the value of _mmdTextBox is bigger then 1999 it should give a MessageBx.Show("Value to high").
If the value is smaller then 0 there should be a MessageBox.Show("Value to low").
This is what I have made so far:
private void _mmdButton_Click(object sender, EventArgs e)
{
var value = _mmdTextBox.Text;
if (value > 1999 && value < 0)
{
MessageBox.Show("Value is to high");
}
else
{
// action
}
}
This is the error that I get when I do it like the code above:
Error 1 Operator '>' cannot be applied to operands of type 'string' and 'int'
int value;
if(Int32.TryParse(_mmdTextBox.Text, out value)
{
if (value > 1999)
{
MessageBox.Show("Value is too high");
}
else if(value < 0)
{
MessageBox.Show("Value is too low");
}
else
{
// action
}
}
else
{
// not a number
}
TextBox.Text returns string. So your value will be string. You can't compare string with an integer using < or > operators.
From MSDN;
All numeric and enumeration types define....
Try to convert your value to int if it is available.
int value;
if(Int32.TryParse(_mmdTextBox.Text, out value)
{
if (value > 1999)
{
MessageBox.Show("Value is too high");
}
if(value < 0)
{
MessageBox.Show("Value is too low");
}
}
C# is an strongly typed language and if you want to compare 2 value . They should be the same type . So you need to be convert text box text to int also you need a validation to be insure that the value which coming from text bot is int ok
I thought this will help full for you
Your if statement could be changed to look like this:
var value = Convert.ToInt32(_mmdTextBox.Text); //Convert to int in order to compare against an int
if (value > 1999)
{
MessageBox.Show("Value is to high");
}
else if (value < 0)
{
MessageBox.Show("Value is to low");
}
else
{
//Action
}
You are comparing the value as type string to type int.
int.TryParse() would be a better option for the int conversion as the user could enter anything. (Like in Erno De Weerd's answer)
You are comparing _mmdTextBox.Text which is string to constant of type int! It is impossible!
You should convert the former to int:
int value;
if(!int.TryParse(_mmdTextBox.Text, out value))
{
MessageBox.Show("Bad integer value in textbox");
return;
}
How can something be > 1999 AND < 0 ?
TryParse might be better for your conversion but this should work:
private void _mmdButton_Click(object sender, EventArgs e)
{
var value = Convert.ToInt32(_mmdTextBox.Text);
if (value > 1999)
{
MessageBox.Show("Value is too high");
}
else if (value < 0)
{
MessageBox.Show("Value is too low");
}
else
{
MessageBox.Show("Value is ok");
}
}
Your problem ist, that value is a string and not a number. You can use Parse or TryParse to solve it.
If you want to use .TryParse() make it look like this example from MSDN:
int number;
bool result = Int32.TryParse(value, out number);
if (result)
{
if (number > 1999 || number < 0)
{
MessageBox.Show("Value is invalid");
}
else
{
// action
}
}
else
{
//Show that the input is not a numeric value
}
Try it for instead of your if condition
if (Convert.ToInt32(value) > 1999 && !Convert.ToInt32(value)< 0)

Convert String To Int in LINQ

I have a LINQ query that queries a DataTable. In the DataTable, the field is a string and I need to compare that to an integer, basically:
if ((electrical >= 100 && electrical <= 135) || electrical == 19)
{
// The device passes
}
the problem is, I am trying to do this in LINQ like this:
var eGoodCountQuery =
from row in singulationOne.Table.AsEnumerable()
where (Int32.Parse(row.Field<String>("electrical")) >= 100 &&
Int32.Parse(row.Field<String>("electrical")) <= 135) &&
Int32.Parse(row.Field<String>("electrical")) != 19 &&
row.Field<String>("print") == printName
select row;
I keep getting the exception:
Input string was not in a correct format
The main problem occurs when electrical == ""
Unfortunately, the framework doesn't provide a nice clean way to handle parsing scenarios where it fails. Of what's provided, they only throw exceptions or use out parameters, both of which does not work well with linq queries. If any one value you're parsing fails, the entire query fails and you just can't really use out parameters. You need to provide a method to handle the parsing without that does not throw and does not require using out parameters.
You can handle this in many ways. Implement it where upon failure, you return some default sentinel value.
public static int ParseInt32(string str, int defaultValue = 0)
{
int result;
return Int32.TryParse(str, out result) ? result : defaultValue;
}
Or what I would recommend, return a nullable value (null indicating it failed).
public static int? ParseInt32(string str)
{
int result;
return Int32.TryParse(str, out result) ? result : null;
}
This simplifies your query dramatically while still leaving it readable.
public bool GetElectricalStatus(string printName)
{
var query =
from row in singulationOne.Table.AsEnumerable()
where row.Field<string>("print") == printName
// using the nullable implementation
let electrical = ParseInt32(row.Field<string>("electrical"))
where electrical != null
where electrical == 19 || electrical >= 100 && electrical <= 135
select row;
return !query.Any();
}
p.s., your use of the Convert.ToInt32() method is incorrect. It is the same as calling Int32.Parse() and does not return a nullable, it will throw on failure.
I would check if the data in the column does not contain leading/trailing whitespaces - i.e. "15 " rather than "15" and if it does (or might do) trim it before trying to convert:
Int32.Parse(row.Field<String>("electrical").Trim())
BTW: not related to the error but I'd use let statement to introduce a local variable and do the conversion once:
let x = Int32.Parse(row.Field<String>("electrical").Trim())
where x >= 100...
I could not get anything to work, so I re-did the whole method:
public bool GetElectricalStatus(string printName)
{
List<object> eGoodList = new List<object>();
var eGoodCountQuery =
from row in singulationOne.Table.AsEnumerable()
where row.Field<String>("print") == printName
select row.Field<String>("electrical");
foreach (var eCode in eGoodCountQuery)
{
if (!string.IsNullOrEmpty(eCode.ToString()))
{
int? eCodeInt = Convert.ToInt32(eCode);
if (eCodeInt != null &&
(eCodeInt >= 100 && eCodeInt <= 135) || eCodeInt == 19)
{
eGoodList.Add(eCode);
}
}
}
if (eGoodList.Count() > 0)
{
return false;
}
else
{
return true;
}
}
The main problem occurs when electrical == ""
Why not make a function that does your evaluation, and call it in your Linq query. Put logic in to check the validity of the data contained within (so if you can't parse the data, it should return false)...
The function:
bool IsInRange(string text, int lower, int upper, params int[] diqualifiers)
{
int value = int.MinValue;
if (!int.TryParse(text, out value)) {
return false;
}
if (!(value >= lower && value <= upper)) {
return false;
}
if (disqualifiers != null && disqualifiers.Any(d => d == value)) {
return false;
}
return true;
}
The Linq query...
var eGoodCountQuery =
from row in singulationOne.Table.AsEnumerable()
where
IsInRange(row.Field<String>("electrical"), 100, 135, 19)
&& row.Field<String>("print") == printName
select row;

getting a registry key and value in C#

Sorry if this is simple, I haven't coded since college. I'm trying to write a program to view registry entries in Windows 7. I want to check to see if the registry value exists first, then check to see what the value is. If it doesn't exist, I want one message, if it does exist, I want one message reflecting a value of 1, and another reflecting a value of 0. I got the code to work if the registry key doesn't exist, but if I add the key and value it crashes. Not sure what I'm doing wrong here. Any suggestions would be appreciated. Here is my code.
using (RegistryKey Key = Registry.LocalMachine.OpenSubKey(#"SYSTEM\CurrentControlSet\services\LanmanServer\Parameters"))
if (Key != null)
{
string val = (string)Key.GetValue("EnableOplocks");
if (val == null)
{
oplockTextBox.Text = "Not Present In Registry";
oplockTextBox.BackColor = Color.Yellow;
}
else if (val == "1")
{
opslockTextBox.Text = "NO";
opslockTextBox.BackColor = Color.Red;
}
else
{
oplockTextBox.Text = "YES";
oplockTextBox.BackColor = Color.Green;
}
}
else
{
MessageBox.Show("");
}
As far as I can tell, the EnableOplocks value for that registry key is a DWORD value, which will give you an int when you use GetValue() to retrieve it. Trying to cast an int to a string will produce an InvalidCastException.
Instead, you should try this:
int? val = Key.GetValue("EnableOplocks") as int?;
if (val == null)
{
// ..
}
else if (val == 1)
{
// ...
}
Or this:
object val = Key.GetValue("EnableOplocks");
if (val == null)
{
// ...
}
else
{
string strVal = val.ToString();
if (strVal == "1")
{
// ...
}
}
In general, please remember to provide all of the error information you have. Saying "it crashes" is not very informative.
The registry can hold data-types other than string. What is happening is you are likely getting a int returned and that is why you are crashing when you attempt to cast a int to a string
Get the value back and store it in a object and have your debugger break. You should then be able to see what datatype is stored in the object and change your code to make the correct cast.
The other option would be use .ToString() instead of casting, you would need to compare the string 1 (like you are now) instead of the value 1. However, I always prefer to just use the correct type instead of turning everything in to strings.
Use follow;
string val = Key.GetValue("EnableOplocks").ToString();
EDIT
using (RegistryKey Key = Registry.LocalMachine.OpenSubKey(#"SYSTEM\CurrentControlSet\services\LanmanServer\Parameters"))
if (Key != null)
{
var val = Key.GetValue("EnableOplocks");
if (val == null)
{
oplockTextBox.Text = "Not Present In Registry";
oplockTextBox.BackColor = Color.Yellow;
}
else if (val.ToString() == "1")
{
opslockTextBox.Text = "NO";
opslockTextBox.BackColor = Color.Red;
}
else
{
oplockTextBox.Text = "YES";
oplockTextBox.BackColor = Color.Green;
}
}
else
{
MessageBox.Show("");
}

Asp.Net : Extended range validation

I'm using Asp.Net 2.0. I have a scenario where i need to check a user input against any of two ranges. For e.g. I need to check a textbox value against ranges 100-200 or 500-600. I know that i can hook up 2 Asp.Net RangeValidators to the TextBox, but that will try to validate the input against both the ranges, an AND condition,if you will. CustomValidator is an option, but how would I pass the 2 ranges values from the server-side. Is it possible to extend the RangeValidator to solve this particular problem?
[Update]
Sorry I didn't mention this, the problem for me is that range can vary. And also the different controls in the page will have different ranges based on some condition. I know i can hold these values in some js variable or hidden input element, but it won't look very elegant.
A CustomValidator should work. I'm not sure what you mean by "pass the 2 ranges values from the server-side". You could validate it on the server-side using a validation method like this:
void ValidateRange(object sender, ServerValidateEventArgs e)
{
int input;
bool parseOk = int.TryParse(e.Value, out input);
e.IsValid = parseOk &&
((input >= 100 || input <= 200) ||
(input >= 500 || input <= 600));
}
You will then need to set the OnServerValidate property of your CustomValidator to "ValidateRange", or whatever you happen to call it.
Is this the sort of thing you're after?
I do not believe this is possible using the standard RangeValidator control.
I did some searching and I believe your best solution is going to be to create your own CustomValidator control which you can include in your project to handle this scenario.
http://www.dotnetjunkies.ddj.com/Article/592CE980-FB7E-4DF7-9AC1-FDD572776680.dcik
You shouldn't have to compile it just to use it in your project, as long as you reference it properly.
You can use the RegularExpressionValidator with the ValidationExpression property set to
Edit: (whoops, 650 and 201 etc. were valid with the old pattern)
^(1\d{2}|200|5\d{2}|600)$
This will test the entered text for 100-200 and 500-600.
I extended the BaseValidator to achieve this. Its fairly simple once you understand how Validators work. I've included a crude version of code to demonstrate how it can be done. Mind you it's tailored to my problem(like int's should always be > 0) but you can easily extend it.
public class RangeValidatorEx : BaseValidator
{
protected override void AddAttributesToRender(System.Web.UI.HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
if (base.RenderUplevel)
{
string clientId = this.ClientID;
// The attribute evaluation funciton holds the name of client-side js function.
Page.ClientScript.RegisterExpandoAttribute(clientId, "evaluationfunction", "RangeValidatorEx");
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range1High", this.Range1High.ToString());
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range2High", this.Range2High.ToString());
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range1Low", this.Range1Low.ToString());
Page.ClientScript.RegisterExpandoAttribute(clientId, "Range2Low", this.Range2Low.ToString());
}
}
// Will be invoked to validate the parameters
protected override bool ControlPropertiesValid()
{
if ((Range1High <= 0) || (this.Range1Low <= 0) || (this.Range2High <= 0) || (this.Range2Low <= 0))
throw new HttpException("The range values cannot be less than zero");
return base.ControlPropertiesValid();
}
// used to validation on server-side
protected override bool EvaluateIsValid()
{
int code;
if (!Int32.TryParse(base.GetControlValidationValue(ControlToValidate), out code))
return false;
if ((code < this.Range1High && code > this.Range1Low) || (code < this.Range2High && code > this.Range2Low))
return true;
else
return false;
}
// inject the client-side script to page
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (base.RenderUplevel)
{
this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "RangeValidatorEx", RangeValidatorExJs(),true);
}
}
string RangeValidatorExJs()
{
string js;
// the validator will be rendered as a SPAN tag on the client-side and it will passed to the validation function.
js = "function RangeValidatorEx(val){ "
+ " var code=document.getElementById(val.controltovalidate).value; "
+ " if ((code < rangeValidatorCtrl.Range1High && code > rangeValidatorCtrl.Range1Low ) || (code < rangeValidatorCtrl.Range2High && code > rangeValidatorCtrl.Range2Low)) return true; else return false;}";
return js;
}
public int Range1Low
{
get {
object obj2 = this.ViewState["Range1Low"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range1Low"] = value; }
}
public int Range1High
{
get
{
object obj2 = this.ViewState["Range1High"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range1High"] = value; }
}
public int Range2Low
{
get
{
object obj2 = this.ViewState["Range2Low"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range2Low"] = value; }
}
public int Range2High
{
get
{
object obj2 = this.ViewState["Range2High"];
if (obj2 != null)
return System.Convert.ToInt32(obj2);
return 0;
}
set { this.ViewState["Range2High"] = value; }
}
}

Categories

Resources