Почему наследование не прокладывает себе путь, я думаю, что оно должно работать?

Просто хотел показать мои коды:

function (name) {
  name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
  var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
  results = regex.exec(location.search);
  return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));

}

8
задан Constantin 9 October 2008 в 11:26
поделиться

17 ответов

Короткий ответ - то, что GetLeg является инвариантным в своем типе возврата. Длинный ответ может быть найден здесь: Ковариантность и контравариантность

Я хотел бы добавить, что, в то время как наследование обычно является первым инструментом абстракции, что большинство разработчиков выходит из своей панели инструментов, почти всегда возможно использовать состав вместо этого. Состав является немного большим количеством работы для разработчика API, но делает API более полезным для его потребителей.

15
ответ дан 3 November 2019 в 12:13
поделиться

Можно достигнуть того, что Вы хотите при помощи дженерика с соответствующим ограничением, как следующее:

abstract class Animal<LegType> where LegType : Leg
{
    public abstract LegType GetLeg();
}

abstract class Leg { }

class Dog : Animal<DogLeg>
{
    public override DogLeg GetLeg()
    {
        return new DogLeg();
    }
}

class DogLeg : Leg { }
0
ответ дан 3 November 2019 в 12:13
поделиться

@Luke

Я думаю Ваше, возможно, наследование недоразумения. Собака. GetLeg () возвратит объект DogLeg.

public class Dog{
    public Leg GetLeg(){
         DogLeg dl = new DogLeg(super.GetLeg());
         //set dogleg specific properties
    }
}


    Animal a = getDog();
    Leg l = a.GetLeg();
    l.kick();

фактический названный метод будет Собакой. GetLeg (); и DogLeg. Удар () (я принимаю метод Leg.kick () существует) там для, при этом заявленным типом возврата является DogLeg, является ненужным, потому что, именно это возвратился, даже если тип возврата для Собаки. GetLeg () является Участок.

0
ответ дан 3 November 2019 в 12:13
поделиться

Вы могли также возвратить интерфейс ILeg, который реализуют и Участок и DogLeg.

0
ответ дан 3 November 2019 в 12:13
поделиться

Важная вещь помнить состоит в том, что можно использовать производный тип каждое место, Вы используете базовый тип (можно передать Собаку любому методу/свойству/полю/переменной, который ожидает Животное),

Давайте возьмем эту функцию:

public void AddLeg(Animal a)
{
   a.Leg = new Leg();
}

Совершенно допустимая функция, теперь давайте вызовем функцию как этот:

AddLeg(new Dog());

Если свойство Dog. Участок не имеет Участка типа, функция AddLeg внезапно содержит ошибку и не может быть скомпилирована.

0
ответ дан 3 November 2019 в 12:13
поделиться

@Brian Leahy, Очевидно, если Вы только воздействуете на него как Участок, там не является никакой потребностью или причиной бросить. Но если существует некоторый DogLeg или Собака определенное поведение, иногда существуют причины, что бросок необходим.

0
ответ дан 3 November 2019 в 12:13
поделиться

Право, я понимаю, что могу просто бросить, но который означает, что клиент должен знать, что у Собак есть DogLegs. То, что я задаюсь вопросом, - то, если существуют технические причины, почему это не возможно, учитывая, что неявное преобразование существует.

0
ответ дан 3 November 2019 в 12:13
поделиться

Возможно, легче видеть проблему с примером:

Animal dog = new Dog();
dog.SetLeg(new CatLeg());

Теперь, когда должен скомпилировать, если Вы - скомпилированная Собака, но мы, вероятно, не хотим такого мутанта.

Связанная проблема, должен Преследовать [] быть Животным [], или IList <Собака> IList <Животное>?

1
ответ дан 3 November 2019 в 12:13
поделиться

C# имеет явные интерфейсные реализации для обращения просто к этой проблеме:

abstract class Leg { }
class DogLeg : Leg { }

interface IAnimal
{
    Leg GetLeg();
}

class Dog : IAnimal
{
    public override DogLeg GetLeg() { /* */ }

    Leg IAnimal.GetLeg() { return GetLeg(); }
}

Если у Вас будет Собака через ссылку Собаки типа, то вызов GetLeg () возвратит DogLeg. Если у Вас будет тот же объект, но ссылка имеет тип IAnimal, то это возвратит Участок.

1
ответ дан 3 November 2019 в 12:13
поделиться

Понятие, которое вызывает Вас проблемы, описано по http://en.wikipedia.org/wiki/Covariance_and_contravariance_ (computer_science)

2
ответ дан 3 November 2019 в 12:13
поделиться

GetLeg () должен возвратить Участок, чтобы быть переопределением. Ваш класс Собаки однако, может все еще возвратить объекты DogLeg, так как они - дочерний класс Участка. клиенты могут затем бросить и воздействовать на них как резкие искривления.

public class ClientObj{
    public void doStuff(){
    Animal a=getAnimal();
    if(a is Dog){
       DogLeg dl = (DogLeg)a.GetLeg();
    }
  }
}
2
ответ дан 3 November 2019 в 12:13
поделиться

Можно использовать дженерики и интерфейсы для реализации этого в C#:

abstract class Leg { }

interface IAnimal { Leg GetLeg(); }

abstract class Animal<TLeg> : IAnimal where TLeg : Leg
 { public abstract TLeg GetLeg();
   Leg IAnimal.GetLeg() { return this.GetLeg(); }
 }

class Dog : Animal<Dog.DogLeg>
 { public class DogLeg : Leg { }
   public override DogLeg GetLeg() { return new DogLeg();}
 } 
3
ответ дан 3 November 2019 в 12:13
поделиться

Это - совершенно допустимое требование иметь подпись, метод переопределения имеет тип возврата, который является подтипом типа возврата в переопределенном методе (уф). В конце концов, они - совместимый тип выполнения.

Но C# еще не поддерживает "ковариантные типы возврата" в переопределенных методах (в отличие от C++ [1998] и Java [2004]).

Необходимо будет работать вокруг и суметь обойтись для обозримого будущего, как Eric Lippert заявил в своем блоге [19 июня 2008]:

Такое различие называют "ковариантностью типа возврата".

у нас нет планов реализовать такое различие в C#.

4
ответ дан 3 November 2019 в 12:13
поделиться
abstract class Animal
{
  public virtual Leg GetLeg ()
}

abstract class Leg { }

class Dog : Animal
{
  public override Leg GetLeg () { return new DogLeg(); }
}

class DogLeg : Leg { void Hump(); }

Сделайте это как это, затем можно усилить абстракцию в клиенте:

Leg myleg = myDog.GetLeg();

Затем, если Вы должны, можно бросить его:

if (myleg is DogLeg) { ((DogLeg)myLeg).Hump()); }

Полностью изобретенный, но точка так, можно сделать это:

foreach (Animal a in animals)
{
   a.GetLeg().SomeMethodThatIsOnAllLegs();
}

Все еще сохраняя способность иметь специальный метод Горба на Резких искривлениях.

3
ответ дан 3 November 2019 в 12:13
поделиться

Собака должна возвратить Участок не DogLeg как тип возврата. Фактическим классом может быть DogLeg, но точка должна разъединиться так, пользователь Собаки не должен знать о DogLegs, они только должны знать об Участках.

Изменение:

class Dog : Animal
{
  public override DogLeg GetLeg() {...}
}

кому:

class Dog : Animal
{
  public override Leg GetLeg() {...}
}

Не Делайте этого:

 if(a instanceof Dog){
       DogLeg dl = (DogLeg)a.GetLeg();

это побеждает цель программировать к абстрактному типу.

Причина скрыть DogLeg состоит в том, потому что функция GetLeg в абстрактном классе возвращает Абстрактный Участок. При переопределении GetLeg, необходимо возвратить Участок. В этом суть наличия метода в абстрактном классе. Для распространения того метода к, он - дети. Если Вы хотите, чтобы пользователи Собаки знали о DogLegs, делают метод под названием GetDogLeg и возвращают DogLeg.

Если Вы МОГЛИ БЫ сделать, как задающий вопрос хочет, то каждый пользователь Животного должен был бы знать обо ВСЕХ животных.

6
ответ дан 3 November 2019 в 12:13
поделиться

Очевидно, Вам будет нужен бросок, если Вы будете воздействовать на поврежденный DogLeg.

12
ответ дан 3 November 2019 в 12:13
поделиться

Не то, чтобы это полезно, но, возможно, интересно отметить, что Java действительно поддерживает ковариантные возвраты, и таким образом, это работало бы точно, как Вы надеялись. Кроме, очевидно, что Java не имеет свойств ;)

2
ответ дан 3 November 2019 в 12:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: