(извлек некоторое объяснение, которое было скрыто в комментариях в другом ответе)
проблема заключается в следующей строке:
this.dom.addEventListener("click", self.onclick, false);
Здесь, Вы передаете функциональный объект, который будет использоваться в качестве обратного вызова. Когда триггер события, функция вызвана, но теперь это не имеет никакой связи ни с каким объектом (это).
проблема может быть решена путем обертывания функции (с, он - ссылка на объект) в закрытии следующим образом:
this.dom.addEventListener(
"click",
function(event) {self.onclick(event)},
false);
, Так как переменная сам была присвоена это , когда закрытие было создано, функция закрытия будет помнить значение сам переменная, когда это звонило в более позднее время.
альтернативный способ решить это состоит в том, чтобы сделать служебную функцию (и избегать использования переменных для привязки это ):
function bind(scope, fn) {
return function () {
fn.apply(scope, arguments);
};
}
обновленный код был бы тогда похож:
this.dom.addEventListener("click", bind(this, this.onclick), false);
Function.prototype.bind
часть ECMAScript 5 и обеспечивает ту же функциональность. Таким образом, можно сделать:
this.dom.addEventListener("click", this.onclick.bind(this), false);
Для браузеров, которые еще не поддерживают ES5, , MDN обеспечивает следующий контейнер :
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP
? this
: oThis || window,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
Плох не сам оператор using - это если вы получите слишком много из них.
Такой оператор, как using System;
редко представляет собой проблему сама по себе, но если у вас много (я бы сказал, более 3-6, в зависимости от того, какие) в одном файле кода, это может быть признаком сильной связи .
Вы могли бы с таким же успехом применить аналогичное эмпирическое правило к количеству ссылок в самом проекте.
Решением сильной связи является программирование интерфейсов и внедрение зависимостей (DI).
1293]. Способ ProgId делать вещи, которые вы помните из VB, был просто COM в действии. По сути, вы использовали этот ProgId, чтобы получить ссылку на экземпляр, реализующий желаемый интерфейс. Обратной стороной было то, что это работало только тогда, когда COM-объект был зарегистрирован повсеместно. Помните ад dll?
Вы по-прежнему можете применить тот же принцип, используя определенные разновидности DI, только теперь интерфейс является типом .NET и не определен в IDL, и вам нужен какой-то контейнер DI для обеспечения конкретной реализации.
использование
- это просто ярлык для пространств имен, они не являются ссылками на внешние файлы. Следовательно, это просто не имеет смысла.
В любом случае, что можно сделать, это иметь интерфейсную DLL (DLL только с интерфейсами), чтобы вы динамически загружали и использовали различные сборки и создавали типы (посредством отражения), которые вы может транслироваться в хорошо известные интерфейсы. Это правильный способ ослабить внешние ссылки, сохранив при этом преимущества строго типизированного языка и раннего связывания.
Взгляните на классы Assembly и AppDomain для загрузки сборок,
Я полагаю, что Боб Мартин на самом деле имеет в виду раннее и позднее связывание.
В .NET позднее связывание возможно через отражение и, в частности, через класс Activator, который позволяет создавать тип во внешней сборке с использованием имени файла или сборки.
Обычно директивы using (а не оператор using) идут рука об руку вместе с прямым обращением к внешней сборке. т.е. Вы добавляете ссылку на сборку, а затем добавляете директивы using, чтобы избежать необходимости вводить полную иерархию пространства имен при использовании внешних типов.
Итак, если вы обнаружите, что в вашем коде есть большое количество директив using вверху, это возможно, что вы напрямую ссылаетесь на многие другие типы и, таким образом, увеличиваете связь / зависимость вашего кода от этих типов.
Я предполагаю, что именно поэтому Боб называет их плохими. Ответ на вопрос "это действительно плохо?" является очень субъективным и зависит от контекста.
В общем, разделение компонентов почти всегда является хорошей целью при разработке программного обеспечения. Это потому, что это позволяет вам изменять части вашей системы с минимальным влиянием на остальную систему. Прочитав одну или две книги Боба Мартинса, я ожидал, что это именно то, что он имеет в виду.
Вы можете использовать отражение:
// Load the assembly
Assembly assembly = Assembly.LoadFrom(@"c:\path\Tools.dll");
// Select a type
Type type = assembly.GetType("Tools.Utility");
// invoke a method on this type
type.InvokeMember("SomeMethod", BindingFlags.Static, null, null, new object[0]);
Вы можете делать то, о чем имеете в виду, посредством отражения. Вы можете загрузить сборку во время выполнения и отразить ее, чтобы получить классы и т. Д. И вызвать их динамически.
Лично я бы не стал этого делать, чтобы избежать спаривания. Для меня это плохое использование отражения, и я бы предпочел добавить его в проект и ссылаться на него, если нет конкретной причины, почему бы этого не сделать. Отражение увеличивает накладные расходы на систему, и вы не получаете преимущества безопасности времени компиляции.