Существует метод для итерации только собственных свойств объекта, не считая его прототипов:
for (var i in array) if (array.hasOwnProperty(i)) {
// do something with array[i]
}
, но он все равно будет перебирать настраиваемые свойства.
В javascript any пользовательское свойство может быть назначено любому объекту, включая массив.
Если требуется итерация по разреженному массиву, следует использовать for (var i = 0; i < array.length; i++) if (i in array)
или array.forEach
с es5shim
.
Модификатор переопределения может использоваться для виртуальных методов и должен использоваться для абстрактных методов. Это означает, что компилятор использует последнюю определенную реализацию метода.
blockquote>public class Base { public virtual void DoIt() { } } public class Derived : Base { public override void DoIt() { } } Base b = new Derived(); b.DoIt(); // Calls Derived.DoIt
будет вызывать
]Derived.DoIt
, если это переопределяетBase.DoIt
.Новый модификатор инструктирует компилятор использовать реализацию вашего дочернего класса вместо реализации родительского класса. Любой код, который не ссылается на ваш класс, но родительский класс будет использовать реализацию родительского класса.
blockquote>public class Base { public virtual void DoIt() { } } public class Derived : Base { public new void DoIt() { } } Base b = new Derived(); Derived d = new Derived(); b.DoIt(); // Calls Base.DoIt d.DoIt(); // Calls Derived.DoIt
Сначала вызовет
Base.DoIt
, затемDerived.DoIt
. Они фактически представляют собой два совершенно разных метода, которые имеют одно и то же имя, а не производный метод, переопределяющий базовый метод.Источник: Блог Microsoft
Разница между двумя случаями заключается в том, что в случае 1 базовый метод DoIt
не становится переопределенным, просто скрытым. Это означает, что в зависимости от типа переменной зависит, какой метод будет вызван. Например:
BaseClass instance1 = new SubClass();
instance1.DoIt(); // Calls base class DoIt method
SubClass instance2 = new SubClass();
instance2.DoIt(); // Calls sub class DoIt method
Это может быть действительно запутанным и приводит к не ожидаемому поведению, и его следует избегать, если это возможно. Таким образом, предпочтительным способом будет случай 2.
В первом случае он вызовет метод DoIt () производного класса, потому что новое ключевое слово скрывает метод базового класса DoIt ().
Во втором случае он вызовет overriden DoIt ()
public class A
{
public virtual void DoIt()
{
Console.WriteLine("A::DoIt()");
}
}
public class B : A
{
new public void DoIt()
{
Console.WriteLine("B::DoIt()");
}
}
public class C : A
{
public override void DoIt()
{
Console.WriteLine("C::DoIt()");
}
}
позволяет создать экземпляр этих классов
A instanceA = new A();
B instanceB = new B();
C instanceC = new C();
instanceA.DoIt(); //A::DoIt()
instanceB.DoIt(); //B::DoIt()
instanceC.DoIt(); //B::DoIt()
Все ожидается выше. Позвольте задать экземпляр B и instanceC в instanceA и вызвать метод DoIt () и проверить результат.
instanceA = instanceB;
instanceA.DoIt(); //A::DoIt() calls DoIt method in class A
instanceA = instanceC;
instanceA.DoIt();//C::DoIt() calls DoIt method in class C because it was overriden in class C
Функциональная разница не будет отображаться в этих тестах:
BaseClass bc = new BaseClass();
bc.DoIt();
DerivedClass dc = new DerivedClass();
dc.ShowIt();
В этом примере, вызванная Doit является той, которую вы ожидаете назвать.
In чтобы увидеть разницу, которую вы должны сделать:
BaseClass obj = new DerivedClass();
obj.DoIt();
Вы увидите, если вы запустите этот тест, который в случае 1 (как вы его определили), DoIt()
в BaseClass
(в том случае, если вы определили его), вызывается DoIt()
в DerivedClass
.
В случае 1, если вы использовали метод DoIt () унаследованного класса, в то время как тип объявлен как базовый класс, вы увидите действие базового класса.
/* Results
Class1
Base1
Class2
Class2
*/
public abstract class Base1
{
public void DoIt() { Console.WriteLine("Base1"); }
}
public class Class1 : Base1
{
public new void DoIt() { Console.WriteLine("Class1"); }
}
public abstract class Base2
{
public virtual void DoIt() { Console.WriteLine("Base2"); }
}
public class Class2 : Base2
{
public override void DoIt() { Console.WriteLine("Class2"); }
}
static void Main(string[] args)
{
var c1 = new Class1();
c1.DoIt();
((Base1)c1).DoIt();
var c2 = new Class2();
c2.DoIt();
((Base2)c2).DoIt();
Console.Read();
}
попробуйте выполнить: (case1)
((BaseClass)(new InheritedClass())).DoIt()
Edit: virtual + override разрешены во время выполнения (поэтому переопределение действительно отменяет виртуальные методы), а новые просто создают новый метод с тем же именем и скрывает старый, он разрешен во время компиляции -> ваш компилятор вызовет метод, который он видит '
Ниже приведена статья в vb.net, но я думаю, что объяснение новых переопределений vs очень легко понять.
https://www.codeproject.com/articles/17477/ the-dark-shadow of of-overrides
В какой-то момент статьи есть следующее предложение:
В общем, Shadows предполагает связанную с этим функцию с вызовом type, в то время как Overrides предполагает реализацию объекта.
blockquote>. Принятый ответ на этот вопрос является совершенным, но я думаю, что эта статья является хорошим примером для лучшего понимания различий между эти два ключевых слова.
Если в производном классе используется ключевое слово override
, то оно переопределяет родительский метод.
Если ключевое слово new
используется в производном классе, то выведите метод, скрытый родительским методом.
Мой способ иметь в виду оба ключевых слова, которые они противоположны друг другу.
override
: ключевое слово virtual
должно быть определено для переопределения метода. Метод, использующий ключевое слово override
, независимо от ссылочного типа (ссылка на базовый класс или производный класс), если он создается с базовым классом, выполняется метод базового класса. В противном случае используется метод производного класса.
new
: если ключевое слово используется методом, в отличие от ключевого слова override
, тип ссылки важен. Если он создается с производным классом, а ссылочный тип - это базовый класс, выполняется метод базового класса. Если он создается с производным классом, а ссылочный тип - это производный класс, выполняется метод производного класса. А именно, это отличие от ключевого слова override
. En passant, если вы забыли или опустите, чтобы добавить новое ключевое слово в метод, компилятор ведет себя по умолчанию при использовании ключевого слова new
.
class A
{
public string Foo()
{
return "A";
}
public virtual string Test()
{
return "base test";
}
}
class B: A
{
public new string Foo()
{
return "B";
}
}
class C: B
{
public string Foo()
{
return "C";
}
public override string Test() {
return "derived test";
}
}
Вызов в основном:
A AClass = new B();
Console.WriteLine(AClass.Foo());
B BClass = new B();
Console.WriteLine(BClass.Foo());
B BClassWithC = new C();
Console.WriteLine(BClassWithC.Foo());
Console.WriteLine(AClass.Test());
Console.WriteLine(BClassWithC.Test());
Выход:
A
B
B
base test
derived test
virtual: указывает, что метод может быть переопределен переопределением функции inheritor
: переопределяет функциональность виртуального метода в базовом классе, предоставляя различные функции.
new: скрывает исходный метод (который не обязательно должен быть виртуальным), обеспечивая различные функциональные возможности. Это нужно использовать только там, где это абсолютно необходимо.
Когда вы скрываете метод, вы все равно можете получить доступ к исходному методу, доведя его до базового класса. Это полезно в некоторых сценариях, но опасно.
В первом случае вы скрываете определение в родительском классе. Это означает, что он будет вызываться только в том случае, если вы имеете дело с объектом как дочерний класс. Если вы примените класс к его родительскому типу, будет вызван метод parent. Во втором случае метод переопределяется и будет вызываться независимо от того, был ли объект включен в качестве дочернего или родительского класса.
Из всего этого новое - самое запутанное. Благодаря экспериментированию новое ключевое слово похоже на предоставление разработчикам возможности переопределить реализацию наследующего класса с реализацией базового класса, явно определяя тип. Это похоже на то, как думать наоборот.
В приведенном ниже примере результат вернет «Производный результат» до тех пор, пока тип явно не будет определен как тест BaseClass, только тогда будет возвращен «Базовый результат».
class Program
{
static void Main(string[] args)
{
var test = new DerivedClass();
var result = test.DoSomething();
}
}
class BaseClass
{
public virtual string DoSomething()
{
return "Base result";
}
}
class DerivedClass : BaseClass
{
public new string DoSomething()
{
return "Derived result";
}
}
У меня был тот же вопрос, и это действительно запутанно, вы должны учитывать, что переопределение и новые ключевые слова работают только с объектами базового класса типа и значением производного класса. В этом случае вы увидите эффект переопределения и новый: Итак, если у вас есть class A
и B
, B
наследуется от A
, вы создаете экземпляр объекта следующим образом:
A a = new B();
Теперь при вызове методы учитывают его состояние. Override: означает, что он расширяет функцию метода, а затем использует метод в производном классе, тогда как новый сообщает компилятору, чтобы скрыть метод в производном классе и вместо этого использовать метод в базовом классе. Вот очень хороший взгляд на эту тему: