How can I test a decimal for null? - c#

I've got this code intended to convert null decimal vals to a "zero" value:
decimal paymentTot = TryConvertToDecimal(boxPaymentAmount.Text);
if ((null == paymentTot) || (paymentTot < 0))
{
paymentTot = 0M; // or simply 0?
}
private decimal TryConvertToDecimal(String incoming)
{
decimal result = 0.0M;
try
{
result = Convert.ToDecimal(incoming);
}
catch
{
; // nada
}
return result;
}
It compiles, but I get this warning: "The result of the expression is always 'false' since a value of type 'decimal' is never equal to 'null' of type 'decimal?'"
I don't grok just what it's trying to tell me. What sort of test do I need to appease the warning emitter and, more importantly, see to it that my code can equate to 'true' when that is the intent?

decimal is a value type and it can't be null.
If you want to have a nullable decimal then use Nullable<decimal> or decimal? which is a wrapper on decimal type, (it is still a value type though).
See: Nullable<T> Structure
You can also have your method for parsing as:
private Nullable<decimal> TryConvertToDecimal(String incoming)
{
Nullable<decimal> returnValue = null;
decimal result;
if (decimal.TryParse(incoming, out result))
{
returnValue = result;
}
return returnValue;
}
Also it is better to use decimal.TryParse if you are going to ignore the exception in parsing.

You don't Need your own Converter for this, use this instead:
decimal paymentTot;
if(!decimal.TryParse(boxPaymentAmount.Text, out paymentTot))
paymentTot = 0;

You possibly want to return a Nullable<decimal> (shorthand decimal?) from TryConvertToDecimal because decimal is a non-nullable value type.
private decimal? TryConvertToDecimal(String incoming)
{
try
{
return Convert.ToDecimal(incoming);
}
catch
{
return null;
}
}
var paymentTot = TryConvertToDecimal(boxPaymentAmount.Text);
if (!paymentTot.HasValue || paymentTot.Value < 0)
{
paymentTot = 0;
}
Note however that by convention TryXXX functions return bool and use an out argument to return the parsed value upon success. One of these built in to the Framework is decimal.TryParse which you might want to use instead:
decimal paymentTot;
if(!decimal.TryParse(boxPaymentAmount.Text, out paymentTot) || paymentTot < 0)
paymentTot = 0;
will default to 0 if the parsing fails or if the parsed value is < 0, as specified in your question. I would suggest this is most likely the solution you are looking for.

Related

Converting to Int in C# leaves the Value as 0

I'm trying convert decimal? to int and storing the result in "DayOffset". But because of some reason the value of "DayOffset" is getting set to 0 when I run my code. A value is passed in numberRangeHigh as 4
This is what my code looks like:
int DayOffset:
try
{
parseSuccess = int.TryParse(numberRangeHigh.ToString(), out DayOffset);
}
catch (Exception ex)
{
_foundationService.LogBusinessError(null, new ParameterBuilder(), ex.Message.Replace(" ", "_"));
return false;
}
Why are you converting to string at all? To convert decimal? to int, you should just use a cast:
int dayOffset = 0;
if (numberRangeHigh != null)
dayOffset = (int)numberRangeHigh.Value;
The code above will truncate the decimal, so 4.7 would become 4. If you want to round, use Convert.ToInt32 instead:
dayOffset = Convert.ToInt32(numberRangeHigh.Value);
As a side note, the correct way to use TryParse is this:
int DayOffset:
if (!int.TryParse(numberRangeHigh.ToString(), out DayOffset))
{
// Handle error...
return false;
}
Assuming numberRangeHigh is of type Decimal, try this:
int DayOffset = Decimal.ToInt32(numberRangeHigh);
For any nullable struct (you mentioned it was a decimal?), it's often a good idea to first check the .HasValue property (in case it's null). You could do something like this:
int dayOffset = (numberRangeHigh.HasValue) ? Convert.ToInt32(numberRangeHigh.Value) : 0;

Whoa, what the TryParse

I've got a Session that contains particular integer values, which are indexed with given controls. Normally, the following would work just fine:
int value;
int.TryParse(Session["Key"].ToString(), out value);
However, I do need to account for null. Where, if the string fails the default out would return a null. Except I noticed that int.TryParse doesn't work with:
int? value = null;
int.TryParse(Session["Key"].ToString(), out value);
So how can you try that parse, if fails it results in the null?
I found this question and the Microsoft Developer Network dictates:
When this method returns, contains the signed integer value
equivalent of the number contained in s, if the conversion succeeded,
or zero if the conversion failed. The conversion fails if the string
parameter is null or String.Empty, is not of the correct format, or
represents a number less than Min Value or greater than Max Value. This
parameter is passed uninitialized.
Which plainly states, if int.TryParse fails the integer will hold a value of zero. In the instance of my usage, zero could be a valid value. So I need null, any thoughts?
Sure; utilize the return value of int.TryParse (which returns if the conversion succeeded or not):
int? retValue = null;
int parsedValue = 0;
if (int.TryParse(Session["Key"].ToString(), out parsedValue))
retValue = parsedValue;
else
retValue = null;
return retValue;
A little verbose I'll admit, but you could wrap it in a function.
int tmp;
int? value = int.TryParse(Session["Key"].ToString(), out tmp) ? (int?)tmp : null;
The problem is the word "null." What does it mean? null could mean the value was indeterminable, an exception was thrown, simply that the value is null, or some other contextual meaning. Your question is a perfect example, because you, yourself, are arbitrarily stating that, in your opinion, null means the parsing of the string failed.
Microsoft's TryParse paradigm is great, but for limited usage. Consider these Scenarios:
string == "89"
string == null
string == "Hello World"
string == ""
string == "2147483650"
Yet, your only options are to assign an Integer or Null to your output, and to return true or false.
Assuming it worked, what are you going to do with that information? Something like this?
int? value = null;
if (int.TryParse(Session["Key"].ToString(), out value)) {
if (value == null)
// Handle "Appropriate" null
else
// Handle appropriate numeric value
}
else {
// Note: value == null here, and TryParse failed
// Handle null...
// What if the reason it failed was because the number was too big?
// What if the string was Empty and you wanted to do something special?
// What if the string was actually junk? Like "(423)322-9876" ?
// Long-Story Short: You don't know what to do here without more info.
}
Consider this NullableInt TryParse example:
public bool TryParseNullableInt(string input, out int? output)
{
int tempOutput;
output = null;
if (input == null) return true;
if (input == string.Empty) return true; // Would you rather this be 0?
if (!int.TryParse(input, out tempOutput))
return false; // What if string was "2147483650"... or "Twenty Three"?
output = tempOutput;
return true;
}
One solution is to use an enumeration TryParse instead of a boolean TryParse:
public ParseStatus TryParseNullableInt(string input, out int? output)
{
int tempInteger;
output = null;
if (input == null) return ParseStatus.Success;
if (input == string.Empty) { output = 0; return ParseStatus.Derived; }
if (!int.TryParse(input, out tempInteger)) {
if (ParseWords(input, out tempInteger)) { // "Twenty Three" = 23
output = tempInteger;
return ParseStatus.Derived;
}
long tempLong;
if (long.TryParse(input, out tempLong))
return ParseStatus.OutOfRange;
return ParseStatus.NotParsable;
}
output = tempInteger;
return ParseStatus.Success;
}
Another problem is the existence of the out variable. Your third option is to use a descriptive monad, something like this:
public Maybe<int?> TryParseNullableInt(string input)
{
if (input == null) return Maybe.Success(null);
if (input == string.Empty) { return Maybe.Derived(0); }
int tempInteger;
if (!int.TryParse(input, out tempInteger)) {
if (ParseWords(input, out tempInteger)) { // "Twenty Three" = 23
return Maybe.Derived(tempInteger);
}
long tempLong;
if (long.TryParse(input, out tempLong))
return Maybe.OutOfRange();
return Maybe.NotParsable();
}
return Maybe.Success(tempInteger);
}
You can use Monads as Single-Enumerable Values, or like so:
Maybe<int?> result = TryParseNullableInt("Hello");
if (result.HasValue) {
if (result.Status == ParseStatus.Success)
// Do something you want...
else if (result.Status == ParseStatus.Derived)
// Do something else... more carefully maybe?
}
else if (result.Status == ParseStatus.OutOfRange)
MessageUser("That number is too big or too small");
else if (result.Status == ParseStatus.NotParsable)
// Do something
With Monads, and possibly enumeration TryParses, you now have all the info you need from a descriptive return and nobody has to guess what null might mean.

Creating a method with a decimal parameter that goes from 0 to 1

Is it posible to create a method with a decimal argument, that only accepts values from 0 to 1?
Example:
public decimal GetSamplingError(decimal percent){
decimal result = 0;
result = 100*percent;
return result;
}
is it posible to control that the parameter percent is compres between 0 and 1?
Thanks and sorry for my bad english.
no there is no way to control parameter's range, what you can do, is control it inside the function itself, and add a comment to the function
public decimal GetSamplingError(decimal percent){
if(percent > 1)
percent = 1;
else if(percent <0)
percent = 0;
return 100*percent;
}
Or raise an ArgumentOutOfRangeException in case if the parameter is not in dsired range, but it depends on how you would like to manage a worklfow of your application.
I would create my own type of Percent with range checks as others have suggested and some additional stuff. That way, Percent is its own entity in your application and everyone knows when and how to use it. A plain decimal might work as well, I prefer the typed approach however.
internal class Percent
{
private readonly decimal _value;
public decimal Value
{
get { return _value; }
}
public Percent(decimal value)
{
_value = (100 * value);
if (value < 0m || value > 1m)
{
throw new ArgumentOutOfRangeException("value");
}
}
public override string ToString()
{
return String.Format("{0}%", _value);
}
public override int GetHashCode()
{
// HashCode implementation;
}
public override bool Equals(object obj)
{
// Equals implementation;
}
}
There is no way of compile-time checking this. The best solution would be to check the argument at run-time:
public decimal GetSamplingError(decimal percent)
{
if (percent < 0m || percent > 1m)
{
throw new ArgumentException("Percent should be between 0 and 1!", "percent");
}
decimal result = 0;
result = 100*percent;
return result;
}
Other than the approach of Tigran, this will throw an Exception when an invalid argument is passed. I prefer this method over just changing the percent-value, becasue it'll actually make you notice that you passed a wrong value.
When you use Code Contracts of Microsoft, then you could add a contract that ensures that the value is in a specific range. When static checking is enabled, you'll get an error message at compile-time.
Contract.Requires(percent > 0m && percent < 1m, "Percent must be between 0 and 1");
You would have to do:
public decimal GetSamplingError(decimal percent){
if (percent < 0m || percent > 1m)
throw new ArgumentOutOfRangeException("percent", "Must be between 0 and 1.");
// rest of method
}
Of course, it is also possible to make your own struct called DecimalBetweenZeroAndOne which is immutable and holds a decimal field which is readonly and where you write a check to guarantee that the value of the field is always in the required range.
It is possible to validate the input and throw exception if value is not what you expected:
decimal getPercentage(decimal val)
{
if (val < 0 || val > 1)
throw new ArgumentException();
return val * 100;
}

What is wrong on this Decimal.TryParse?

Code :
Decimal kilometro = Decimal.TryParse(myRow[0].ToString(), out decimal 0);
some arguments are not valid?
out decimal 0 is not a valid parameter - 0 is not a valid variable name.
decimal output;
kilometro = decimal.TryParse(myRow[0].ToString(), out output);
By the way, the return value will be a bool - from the name of the variable, your code should probably be:
if(decimal.TryParse(myRow[0].ToString(), out kilometro))
{
// success - can use kilometro
}
Since you want to return kilometro, you can do:
decimal kilometro = 0.0; // Not strictly required, as the default value is 0.0
decimal.TryParse(myRow[0].ToString(), out kilometro);
return kilometro;
Well, the decimal.TryParse returns a bool type - so you need to do something like:
Decimal kilometro;
// if .TryParse is successful - you'll have the value in "kilometro"
if (!Decimal.TryParse(myRow[0].ToString(), out kilometro)
{
// if .TryParse fails - set the value for "kilometro" to 0.0
kilometro = 0.0m;
}
The correct usage of the TryParse statement is given below.
You must declare the decimal first and then pass it into the TryParse method. If the TryParse succeeds, kilometro will be the new value, otherwise it will be zero. I believe that was your desired outcome.
decimal kilometro = 0;
if (Decimal.TryParse(myRow[0].ToString(), out kilometro))
{
//The row contained a decimal.
}
else {
//The row could not be parsed as a decimal.
}
Just as an additional answer, you can now declare out parameters inline.
if (decimal.TryParse(myRow[0].ToString(), out decimal outParamName))
{
// do stuff with decimal outParamName
}

Differentiating between cases where user enters '0' or leaves TextBox empty

Well the question title may not be self explanatory, so let me go ahead and elaborate.
Consider, a TextBox that accepts only numeric value or is left empty. The value(text) entered is stored in an integer(int32) variable. The problem arises when the user enters the digit 0 or leaves the TextBox empty, as the conversion from string to int, converts an empty string to "0" as well.
So my question stands: How do I differentiate the 2 scenarios?
EDIT I figured a lot of questions may be answered by the code and exact problem(as I see it)
if (txtOtherId.Text == string.Empty)
{
otherId = Convert.ToInt32(null);
}
else
{
otherId = Convert.ToInt32(txtOtherId.Text);
}
How about an extension method?
public static class Extensions
{
public static bool TryGetInt(this TextBox tb, out int value)
{
int i;
bool parsed = int.TryParse(tb.Text, out i);
value = i;
return parsed;
}
}
Usage:
int i;
if (textBox1.TryGetInt(out i))
{
MessageBox.Show(i.ToString());
}
else
{
// no integer entered
}
What have you tried? Can we see your code?
Now, I tried the following:
int i;
i = Convert.ToInt32(""); // throws, doesn't give zero
i = int.Parse(""); // throws, doesn't give zero
bool couldParse = int.TryParse("", out i); // makes i=0 but signals that the parse failed
So I can't reproduce. However, if I use null instead of "", the Convert.ToInt32 does convert into zero (0). However, Parse and TryParse still fail with null.
UPDATE:
Now that I see your code. Consider changing the type of otherId from int to int? where the question mark makes it a nullable type. Then:
if (txtOtherId.Text == "")
{
otherId = null; // that's null of type int?
}
else
{
otherId = Convert.ToInt32(txtOtherId.Text); // will throw if Text is (empty again or) invalid
}
If you want to be sure no exceptions can happen, do this:
int tmp; // temporary variable
if (int.TryParse(txtOtherId.Text, out tmp))
otherId = tmp;
else
otherId = null; // that's null of type int?; happens for all invalid input
You could use a nullable int, and then have blank string be null.
int? myValue = String.IsNullOrEmpty(myTextbox.Text)
? (int?)null
: int.Parse(myTextbox.Text);
For clarity, the above is equivalent to
int? myValue = null;
if(!String.IsNullOrEmpty(myTextbox.Text))
{
myValue = int.Parse(myTextbox.Text);
}
Assuming that it is indeed a textbox...
string result = myTextBox.Text;
if (string.IsNullOrEmpty(result))
// This is an empty textbox
else
// It has a number in it.
int i = int.Parse(result);
There're 2 simple approaches how to do it:
string inputText="";
int? i=null;
if (!string.IsNullOrWhiteSpace(inputText))
i = int.Parse(inputText);
int i2;
bool ok = int.TryParse(inputText, out i2);

Categories