I'm currently trying to implement properties and in particular limiting my setter. For example, i have a 'Money' float field that i'd like it so you can add/subtract values to it but when it's at 0 make it so that it can no longer be subtracted but it can however still be added to.
I see that in the code below that once 'Money' reaches 0 it'll be always stuck at 0. Is there some way to check whether the setter is being added to? I understand that you can check it in the AddMoney or SubtractMoney methods but was more curious if it's possible to do so in the setter.
public float Money {
get {
return this._money;
}
set {
if (_money <= 0){
_money = 0;
} else {
_money = value;
}
}
}
void AddMoney(float addAmount){
Money += addAmount;
}
void SubtractMoney(float subtractAmount){
Money -= subtractAmount;
}
Try to test if the value is negative don't change the Money value :
set {
if (value >= 0)
{
_money = value;
}
else
{
//You may throw exception, or log a warning
}
}
Related
For the code below, both WriteLine results outputs are 30.
I do not know why the second result is 30 too.
I think if the value is -1, then the program runs out of the curly brace { return; }, and moves to the next line after {}.
Is it correct?
class Program
{
static void Main(string[] args)
{
Person pp = new Person();
pp.Age = 30;
// Output is 30
Console.WriteLine("the age is {0}", pp.Age);
pp.Age = -1;
// Output is 30 again
Console.WriteLine("the age is {0}", pp.Age);
}
}
class Person
{
private int age;
public int Age
{
set
{
if (value < 0)
{
// An empty return statement
return;
}
// if the value is -1, does it go through this line?
this.age = value;
}
get
{
return this.age;
}
}
}
The return keyword returns control out of the function (regardless of how many nested scopes you are in). This "bail-out" approach is one reason why early returns are considered bad practice. So basically, your program flows like this:
Call setter with 30
value > 0, skip what is in {}
Set backing field to 30
Print property (still 30)
Call setter with -1
value < 0, execute what is in {}
Return, function execution stops and returns to the caller
Print property (still 30 since nothing got set)
If you are doing validation in your setter, throwing an exception is a much better approach.
The return statement exits the property setter before setting the age value. Nothing is returned, as a setter is like a void method. It looks like you don't want to set an age less than 0, which makes sense.
Some apps decide to throw an ArgumentException in cases like this rather than silently failing.
Your setter is just returning if the value is less than 0 so you never set the age when you attempt to set it as -1. The setter should be:
public int Age {
set { age = value; }
}
Unless you don't want to set age if it's less than 0 you would want to throw an exception:
public int Age {
set {
if (value < 0)
throw new ArgumentException();
age = value;
}
}
return will cause a method to immediately exit a method, not merely leave a scope in { }.
There are some cases you want to exit a scope, but not a method. That is done with break, but works in loops.
for (;;)
if (condition)
break; // breaks out of the loop
I think what you are trying to do is protect age from negative values. I recommend using exceptions.
public int Age
{
set
{
if (value < 0)
throw new InvalidArgumentException("Age cannot be negative");
age = value;
}
get
{
return age;
}
}
Using C#, I have a few custom classes where I need to be able to detect integer overflows and return a default minimum or maximum value depending on if the overflow was due to the result being over the maximum value or under the minimum value. I can't seem to find a suggestion on how to detect the "type" of overflow that occurs anywhere.
The classes are divided between two general types: ones that use signed values, and ones that use unsigned values.
As an example, here is one of the classes that deals with Int32 values:
public class Stat32Tf : IStat32T<float>
{
#region fields
private int baseValue, baseAdjustment;
private float baseMultiplier;
#endregion
#region ctors
public Stat32Tf()
{
baseValue = 0;
baseAdjustment = 0;
baseMultiplier = 1f;
}
public Stat32Tf(int baseValue, int baseAdjustment = 0, float baseMultiplier = 1f)
{
this.baseValue = baseValue;
this.baseAdjustment = baseAdjustment;
this.baseMultiplier = baseMultiplier;
}
#endregion
#region properties
public int BaseValue
{
get
{
return baseValue;
}
set
{
baseValue = value;
}
}
public int BaseAdjustment
{
get
{
return baseAdjustment;
}
set
{
baseAdjustment = value;
}
}
public float BaseMultiplier
{
get
{
return BaseMultiplier;
}
set
{
baseMultiplier = value;
}
}
public int TruncValue
{
get
{
return (int)Value;
}
}
public float Value
{
get
{
return (baseValue + baseAdjustment) * baseMultiplier;
}
}
#endregion
}
As you can see, the idea of the class is to hold a base value, an adjustment value, and a multiplier value, and return the aggregate value in the Value property. (The TruncValue property just, as it suggests, returns the truncated whole value, dropping any fractional values).
The goal is to handle overflows in the "get" accessor of the Value property and, if the result is over the max int value, return int.MaxValue and if it is under the min value, return int.MinValue, all without throwing the actual overflow error. The part that's making it tricky for me is that the adjustment values and multipliers could be negative values as well (as per the design requirement).
What is a safe way to achieve this? I have not been able to find any resources that address this kind of situation. I'm guessing some sort of arithmetic algorithm will need to be used to determine of results will be over or under.
There are only a limited number of cases where it could underflow:
If baseValue and baseAdjustment are both negative -> If Int.MinValue - baseAdjustment > baseValue then you have an underflow.
If baseValue + baseAjustment is negative and baseMultiplier is positive -> If an overflow exception is raised, then it can only be an underflow.
If baseValue + baseAdjustment is positive but baseMultiplier is negative -> If an overflow exception is raised, then it can only be an underflow.
If you want to avoid raising/catching exception, then it might be a bit more complicated (you may want to cast the result as long and compare it against Int.MaxValue; that way it'll only raise an exception if the result goes over Long.MaxValue).
Floats are pretty big. Are you expecting the get value to overflow or do you expect the cast to int to overflow? If it's just the cast something similar to the following code might work.
//This answer is wrong, see below.
public int TruncValue
{
get
{
if (Value > (float)int.MaxValue)
{
return int.MaxValue
}
else if (Value < (float)int.MinValue)
{
return int.MinValue
}
else
{
return (int)Value;
}
}
}
Although you might need some additional handling for the edge cases.
Edit - I played around with this in some code and found some behavior that I didn't expect, but apparently it is in the specification.
For example,
var Value = int.MaxValue + int.MaxValue //Ends up returning -2 with no exception in debug mode.
var MaxCalculatedValue = (int.MaxValue + int.MaxValue) * float.MaxValue //Ends up returning something like -3.4... ^38.
You really might need to up cast everything into a double and then check to see if the result is greater than or less than an int.
So it might look something like this:
public float Value
{
get
{
var result = ((double)baseValue + (double)baseAdjustment) * (double)baseMultiplier;
if (result > (double)int.MaxValue)
{
return (float)int.MaxValue)
}
if (result < (double)int.MinValue)
{
return (float)int.MinValue)
}
return (float)result;
}
}
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;
}
I get the exception "Input string was not in correct format". I want to handle that exception and add my own error. The input should be an int. Where should I do this? I have an objectdatasource with listview and I'm having trouble getting the textbox.text from the code behind so I can use tryParse.
Your property is of type Int32. You cannot assign anything else than a valid integer to this property. Now if you have some user input which is under the form of a string and then you need to assign it to the integer property you could use the int.TryParse method to ensure that the value entered by the user is a valid integer.
For example:
string someValueEnteredByUser = ...
int value;
if (!int.TryParse(someValueEnteredByUser, out value))
{
// the value entered by the user is not a valid integer
}
else
{
// the value is a valid integer => you can use the value variable here
}
Number is always an int, it is defined that way...
You probably want to validate the content of a string. Easiest way is to parse it into an int:
int number;
if(!int.TryParse(yourString, out number))
{
Not an int!
}
'value' will always be of the same type as your variable. Thus having this:
private bool mabool = false;
public bool MaBool
{
get { return mabool; }
set { mabool = value; }
}
Won't ever crash. This because, as I said, value will be the same type of the variable. In this case, value is a boolean.
Try it with a class:
public class Rotator
{
public Roll, Pitch, Yaw;
// Declarations here (...)
}
private Rotator rotation = new Rotator();
public Rotator Rotation
{
get { return rotation; }
set
{
// Since value is of the same type as our variable (Rotator)
// then we can access it's components.
if (value.Yaw > 180) // Limit yaw to a maximum of 180°
value.Yaw = 180;
else if (value.Yaw < -180) // Limit yaw to a minimum of -180°
value.Yaw = -180;
rotation = value;
}
}
As seen on the second example, value is a Rotator, thus we can access it's components.
I have a user control with some public properties. A particular property is an integer, but must only accept positive values that are less than a const max value. At present I do the following:
private int markerwidth = 2;
[DefaultValue(2), Category("Appearance"), Description("Size of position marker")]
public int MarkerWidth
{
get
{
return this.markerwidth;
}
set
{
if (value > 0 && value <= MAXMARKERWIDTH)
{
this.markerwidth = value;
}
}
}
This does the job, but fails silently. I guess I could add logic to use 0 for negative values and the max value for those that exceed it, but it's still not ideal.
By way of contrast, the TabValue property (inherited from UserControl) complains if I try to set a negative value at design time (and presumably at run time).
If this achieved with a normal exception? Or is there a better way? An attribute maybe?
The most optimal way is to achieve via exception. Just continue your code
if (value > 0 && value <= MAXMARKERWIDTH)
{
this.markerwidth = value;
}
else
{
throw new ArgumentOutOfRangeException("Invalid value. Value must be between 0 and " + MAXMARKERWIDTH.ToString());
}
EDIT
Yes, Wiktor Zychla is absolutely right! I corrected the answer.
There is a builtin ArgumentOutOfRangeException, I guess it fits here.