问题
[Edit: I realized that the parameter that is failing is actually a double and not an integer. None of the integer timers fail according to the logs. Most of the timers and parameters are integers, but not all. Doubles are not atomic and the lack of locking may be the issue after all.]
I have an application that uses a class that contains properties for configurable values. Most of the properties being used in the app are derived. The values are set at start up and not changed while the main portion of the application is running.
private int _TimerInterval;
public int TimerInterval { get { return _TimerInterval; } }
private int _Factor1;
public int Factor1 {
set {
_Factor1 = value;
_TimerInterval = _Factor1 * _Factor2;
}
get { return _Factor1; }
}
private int _Factor2;
public int Factor2 {
set {
_Factor2 = value;
_TimerInterval = _Factor1 * _Factor2;
}
get { return _Factor2; }
}
I find that very rarely the value returned is apparently zero because of an exception.
Exception Message: '0' is not a valid value for 'Interval'. 'Interval' must be greater than 0.
Exception Target Site: set_Interval
The calling code looks lime this:
exitTimer.Interval = _config.TimerInterval;
The program is multi-threaded but the call to the individual property is only used in one thread. Other properties of the class are called in other threads. I do see the issue on other timers with similar properties.
If I trap the exception and retry the assignment it works.
Could there be something happening at my timer that would cause the execption other than the property returning zero?
Update #1 - More code was requested
Each field is defined as a cfXXX
(Configuration Field) constant. This ensures we don't misspell the field names. A corresponding default value for each property is defined as DefXXX
. The PareseXXX
functions (ParseInt
in this sample) accepts the string value from the configuration lookup and converts it to the corresponding value type or the provided default if it fails. Failure would be from a missing XML record (new configuration option) or one that was incorrectly edited.
Code to load initial configuration data:
// Main Form
public fMain()
{
InitializeComponent();
config = new ConfigData();
config.LoadConfig();
// Other initializations
}
//ConfigData Class
// XML config field names
private const string cfFactor1 = "Factor1";
private const string cfFactor1 = "Factor2";
private const string cfFactor3 = "Factor3";
private const string cfFactor4 = "Factor4";
//Default values
private const int DefFactor1 = 1;
private const int DefFactor2 = 50;
private const int DefFactor3 = 1;
private const int DefFactor4 = 25;
public void LoadConfig()
{
Factor1 = ParseInt(ConfigurationManager.AppSettings[cfFactor1], DefFactor1);
Factor2 = ParseInt(ConfigurationManager.AppSettings[cfFactor2], DefFactor2);
Factor3 = ParseInt(ConfigurationManager.AppSettings[cfFactor3], DefFactor3);
Factor4 = ParseInt(ConfigurationManager.AppSettings[cfFactor4], DefFactor4);
}
int ParseInt(string numberString, int aDefault = 0)
{
int result;
if (!int.TryParse(numberString, out result)) {
result = aDefault;
}
return result;
}
回答1:
The problem was that the premise was wrong. The properties that failed were actually floats and not integers. Embarrassing. As expected adding locks to the properties for those items cured the problem. The integer timers never failed.
I would have just deleted the question at this point, but it already has answers. So let it be a lesson on double checking assumptions.
回答2:
If you want to assign these factors one time for each instance, before the instance is used... Do that in a constructor.
If you want to assign these factors one time for the type, before any instances are created... Do that in a static constructor.
Don't share mutable instances between threads.
回答3:
_TimerInterval is 0 when just Factor1 or Factor2 is set.
x * 0 = 0
来源:https://stackoverflow.com/questions/19095042/why-would-an-integer-property-sometimes-return-a-0