Функция dateFromString возвращает NSDate, а не NSString. Вы должны изменить,
NSDate * theDate = [dateFormatter dateFromString: datetemp];
По этому поводу много раз обсуждали.
Короче говоря: вы не можете гарантировать, что обработчик будет действительным даже при выполнении этой копии / check for null / execute step.
Проблема в том, что если OnTemperaChange не зарегистрирован между временем, когда вы его копируете, и временем, когда вы выполняете копию, то, вероятно, вы не хотите, чтобы слушатель запускался в любом случае .
Вы также можете просто сделать:
if (OnTemperatureChange != null )
{
OnTemperatureChange ( value );
}
И обработать исключение нулевой ссылки.
Иногда я добавляю обработчик по умолчанию, который ничего не делает, просто чтобы предотвратить исключение нулевой ссылки, но это серьезно влияет на производительность, особенно в случае, если другой обработчик не зарегистрирован.
Я полагаюсь на Эрика Липперта .
В моем первоначальном ответе упоминалось использование обработчиков по умолчанию, но я не рекомендовал использовать временную переменную, что, как я теперь согласен, также является хорошей практикой, согласно статье.
Существует причина того, что указанный вами код рекомендуется вместо версии C. Ross. Однако Джон также прав в том, что есть еще одна проблема, если событие тем временем не зарегистрировано. Блог, на который я указал, рекомендует обработчику гарантировать, что они могут быть вызваны даже после отмены регистрации.
Во-первых, вы на самом деле не публикуете событие - так что в настоящий момент ваш код «подвержен риску» того, что люди полностью его испортят. Это должно быть:
public event TemperatureChangeHandler CurrentTemperatureChanged;
Имя «CurrentTemperatureChanged» важно для привязки данных (существует соглашение, которое использует среда выполнения - учитывая свойство Foo, она будет искать FooChanged). Однако , ИМО, это должен быть обычный обработчик событий
. Привязка данных будет искать EventHandler
, но что более важно: вы фактически не даете никакой информации в том случае, если подписчик не может получить ее, просто взглянув на obj.CurrentTemperature
.
Я дам остальную часть ответа в терминах TemperatureChangeHandler
, но я бы посоветовал вам (снова) переключиться на EventHandler
:
public event EventHandler CurrentTemperatureChanged;
Подход:
TemperatureChangeHandler handler = CurrentTemperatureChanged;
if(handler != null) handler(value);
разумен, но (согласно другим ответам) существует небольшой риск того, что абоненты, которые думают, что они отключились, получают событие. Маловероятно в действительности.
Другой подход - метод расширения:
public static class TemperatureChangeExt {
public static void SafeInvoke(this TemperatureChangeHandler handler,
float newTemperature) {
if (handler != null) handler(newTemperature);
}
}
Затем в своем классе вы можете просто использовать:
if (currentTemperature != value) {
currentTemperature = value;
CurrentTemperatureChanged.SafeInvoke(value);
}
Я просто вижу небольшой рефакторинг, который можно было бы провести, но в остальном все выглядит неплохо ...
class Thermostat
{
public delegate void TemperatureChangeHandler ( float newTemperature );
public TemperatureChangeHandler OnTemperatureChange { get; set; }
float currentTemperature;
public float CurrentTemperature
{
get { return this.currentTemperature; }
set
{
if (currentTemperature != value)
{
currentTemperature = value;
if (this.OnTemperatureChange != null )
{
this.OnTemperatureChange.Invoke( value );
}
}
}
}
}
Если класс Thermostat не должен быть потокобезопасным, тогда да, приведенный выше код в порядке - пока есть только один поток, обращающийся к этому экземпляру Thermostat, для OnTemperaChange нет возможности стать незарегистрированным между тестом на null и вызовом события.
Если вам нужно сделать термостат потокобезопасным, то вы можете прочитать следующую статью (в новинку для меня, похоже, хорошо прочитано):
http://www.yoda.arachsys.com/csharp/events.html
Для записи, рекомендация состоит в том, что вы разрабатываете свои классы так, чтобы они не были потокобезопасными, если безопасность потоков явно не требуется, поскольку это может значительно увеличить сложность вашего кода.