Почему конструктор экземпляра C # имеет имя, отличное от возвращаемого типа?

1

Иногда я вижу код С#:

Создается экземпляр, который затем вызывает конструктор, который не совпадает с конструктором типа.

Например:

Person somebody = new Member();

Какие возможные случаи могут возникнуть, и почему это желательно?

(Я думал, что это связано с вызовом конструктора базового класса, но я не мог получить это для компиляции)

  • 0
    Участник - детский класс Person. Человек мог быть абстрактным.
  • 0
    Это похоже на object o = new String(); или, более интуитивно, Animal fido = new Dog();
Показать ещё 3 комментария
Теги:
constructor
instantiation

4 ответа

3
Лучший ответ

Член наследования от Person или Person - это слабо названный интерфейс и Member реализует его:

Подробнее о наследовании: http://msdn.microsoft.com/en-gb/library/ms173149(v=vs.80).aspx http://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)

Дополнительные сведения о интерфейсах: http://msdn.microsoft.com/en-us/library/ms173156.aspx http://en.wikipedia.org/wiki/Protocol_(object-oriented_programming)

Вы можете определить следующее с помощью наследования:

public class Person
{
    public string Name { get; set; }
    public DateTime DateOfBirth { get; set; }
}

public class Adult : Person
{
    public string Workplace { get; set; }
}

public class Child : Person
{
    public List<string> Toys { get; set; }
}

А затем, если вы создадите экземпляр Adult (Adult a = new Adult();), у вас будет доступ к свойствам Name, DateOfBirth и Workplace. Аналогично с ребенком у вас будет свойство Toys.

Кроме того, вы можете сохранить список лиц, который содержит как взрослых, так и детей:

List<Person> people = new List<Person>();
people.Add(new Adult() { Name = "Adult", DateOfBirth = DateTime.Now, Workplace = "Microsoft" });
people.Add(new Child() { Name = "Child", DateOfBirth = DateTime.Now, Toys = new List<string> { "Car", "Train" } });

и затем вы можете пройти через каждую распечатку имени и даты рождения:

foreach(Person p in people)
{
    Console.WriteLine(p.Name + ", " + p.DateOfBirth.ToString("dd/MMM/yy"));
    if(p is Child)
    {
        Console.WriteLine(p.Name + " has the following toys: " + string.Join(", ", ((Child)p).Toys));
    }
    else if(p is Adult)
    {
        Console.WriteLine(p.Name + " works at " + ((Adult)p).Workplace;
    }
}

Интерфейсы в основном определяют контракт (т. IPerson Объект, который реализует IPerson, предоставит реализации для своих методов). Это похоже на сетевую карту: существует стандарт того, как они разговаривают с сетью, но как они работают внутри, зависит от производителя, если они обеспечивают ожидаемое поведение. Интерфейсы не могут иметь в них никакой логики или хранить какие-либо данные, они просто рекламируют то, что обеспечивает реализация этого интерфейса.

public interface IPerson
{
    string Name { get; set; }
    DateTime DateOfBirth { get; set; }
}

public class Adult : IPerson
{
    public string Name { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string Workplace { get; set; }
}

public class Child : IPerson
{
    public string Name { get; set; }
    public DateTime DateOfBirth { get; set; }
    public List<string> Toys { get; set; }
}

Существуют также абстрактные классы, которые обеспечивают некоторые функциональные возможности интерфейсов, но могут реализовывать некоторую логику. Единственное, что следует отметить во всем этом, это то, что класс может быть получен только из (т.е. наследуется) от одного класса, хотя этот класс может наследовать от другого класса. Однако вы можете реализовать несколько интерфейсов.

  • 0
    Итак, используя ваш пример, Child someOne = new Person () не имеет смысла, потому что, конечно, дочерний объект является личностью и наследует эти атрибуты, и конструктор Person (), вероятно, в любом случае будет слишком общим, и именно поэтому Person someOne = new Child () делает больше смысла; потому что мы говорим «вот человек, и давайте теперь укажем, что это потомок, через конструктор Child (). Если это так, то почему бы просто не сделать Child someOne = new Child ()?
  • 0
    Кстати, спасибо за ваш глубокий пример. Мне придется разобраться с аспектами «за рамками» с течением времени.
Показать ещё 2 комментария
2

Это действительно, если Person является базовым классом Member

Аналогично это также справедливо:

Object o = new Member();
  • 0
    +1 за пример, который кристально чистый.
1

Ваш вопрос не является вопросом о конструкторах. Это все о неявных преобразованиях. В вашем заявлении:

Person somebody = new Member();

правая часть оператора = явно имеет Member типа (время компиляции). Однако переменная у somebody есть (время компиляции) Person. Это законно, только если существует неявное преобразование из Member в Person. Тогда код действительно похож на Person somebody = (Person)(new Member()); кроме того, что "литье" невидимо.

Теперь самым обычным неявным преобразованием является ссылочное преобразование из class в его (прямой или косвенный) базовый класс или в интерфейс, который он реализует.

Существует несколько иное неявное преобразование, преобразование бокса из struct или enum в его базовый класс или интерфейс.

Существуют также пользовательские неявные преобразования, которые являются своего рода методами (написанными с implicit operator).

Есть более неявные преобразования, например, из значения типа V в версию Nullable<>, обычно записываемую как V? , Но было бы странно, если бы Person было просто using псевдоним для Member? , поэтому этот пример не реалистичен в вашем примере. Другой, который редко упоминается в этом примере, - это "расширение" преобразования, например, от int до long.

Прочтите спецификацию языка С#, чтобы узнать больше о том, какие преобразования существуют.

0

Member класса, вероятно, выглядит следующим образом...

public class Member : Person {}

Где Member происходит от Person.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню