Статья Википедии. Мне инверсия управления поворачивает Ваш последовательно записанный код и превращает его в структуру делегации. Вместо Вашей программы, явно управляющей всем, Ваша программа настраивает класс или библиотеку с определенными функциями, которые назовут, когда определенные вещи происходят.
Это решает дублирование кода. Например, в былые времена Вы вручную записали бы свой собственный цикл событий, опросив системные библиотеки относительно новых событий. В наше время, самые современные API, которые Вы просто говорите системным библиотекам, какие события Вы интересуетесь, и это сообщит, когда они произойдут.
Инверсия управления является практическим способом уменьшить дублирование кода, и если Вы копируете весь метод и только изменить маленькую часть кода, можно рассмотреть занятие им с инверсией управления. Инверсия управления сделана легкой на многих языках через понятие о делегатах, интерфейсах или даже необработанных указателях функции.
не уместно использовать во всех случаях, потому что поток программы может быть более тверд следовать, когда записано за этим путем. Это - полезный путь к методам разработки при записи библиотеки, которая будет снова использована, но это должно использоваться экономно в ядре собственной программы, если это действительно не решает проблему дублирования кода.
ОБНОВЛЕНИЕ: Этот вопрос был темой моего блога 27 мая 2010 года . Спасибо за отличный вопрос!
Здесь очень много очень запутанных ответов. Попробую точно ответить на ваш вопрос. Давайте упростим это:
object value = whatever;
bool condition = something;
decimal result = (decimal)(condition ? value : 0);
Как компилятор интерпретирует последнюю строку? Проблема, с которой сталкивается компилятор, заключается в том, что тип условного выражения должен быть согласован для обеих ветвей ; правила языка не позволяют вам возвращать объект в одной ветке и int - в другой. Возможные варианты: объект и int. Каждый int может быть преобразован в объект, но не каждый объект может быть преобразован в int, поэтому компилятор выбирает объект. Следовательно, это то же самое, что и
decimal result = (decimal)(condition ? (object)value : (object)0);
Следовательно, возвращаемый ноль - это заключенное в рамку целое число.
Затем вы распаковываете int в десятичное. Недопустимо распаковывать упакованные int в десятичные числа. Чтобы узнать, почему, см. Статью в моем блоге по этой теме:
По сути, ваша проблема в том, что вы действуете так, как если бы преобразование в десятичное было распределено, например:
decimal result = condition ? (decimal)value : (decimal)0;
Но поскольку мы Я видел, что
decimal result = (decimal)(condition ? value : 0);
означает не это. Это означает «превратить обе альтернативы в объекты, а затем распаковать получившийся объект».
Разница в том, что компилятор не может определить тип данных, который хорошо соответствует между Object
и Int32
.
Вы можете явно приведите значение int
к объекту
, чтобы получить тот же тип данных во втором и третьем операндах, чтобы он компилировался, но couse означает, что вы упаковываете и распаковываете значение:
result = (decimal)(valueFromDatabase != DBNull.value ? valueFromDatabase : (object)0);
Это скомпилируется, но не запустится. Вы должны упаковать десятичное значение, чтобы распаковать его как десятичное значение:
result = (decimal)(valueFromDatabase != DBNull.value ? valueFromDatabase : (object)0M);
Типом оператора будет объект, и в случае, если результат должен быть 0, он будет неявно упакован. Но литерал 0 по умолчанию имеет тип int, поэтому вы вставляете int. Но с явным приведением к десятичному виду вы пытаетесь распаковать его, что не разрешено (упакованный тип должен сильно совпадать с тем, к которому вы вернулись). Вот почему вы можете получить исключение.
Вот отрывок из спецификации C #:
Второй и третий операнды оператора?: Управляют типом условного выражения. Пусть X и Y - типы второго и третьего операндов. Затем,
Ваша строка должна быть такой:
result = valueFromDatabase != DBNull.value ? (decimal)valueFromDatabase : 0m;
0m - десятичная константа для нуля
Обе части условного оператора должны оценивать один и тот же тип данных
Часть x: y требует общего типа, значение базы данных, вероятно, представляет собой какое-то число с плавающей точкой, а 0 - это внутр. Это происходит до преобразования в десятичное. Попробуйте ": 0.0" или ": 0D".
Если я не ошибаюсь (что очень возможно), это на самом деле 0, который вызывает исключение, и это связано с .NET (безумно), предполагающим тип литерала, поэтому вам нужно указать 0m, а не просто 0.
См. MSDN для получения дополнительной информации.
Есть два разных типа, которые компилятор может решить (во время компиляции), какой из них преобразовать в десятичное. Он не может этого сделать.