Разбираться с проблемой наследования - PullRequest
2 голосов
/ 26 марта 2009

Я хочу расширить базовый класс в C # с некоторыми дополнительными функциями. У меня есть существующий код, который возвращает массив объектов базового класса (Account), которые мне нужно преобразовать в расширенную версию.

Итак, у меня есть расширенная версия:

class AccountXtra : Account
{
    public int Period { get; set; }
    public int Visitors { get; set; }
    public string ContactName { get; set; }
}

Все хорошо.

НО, как мне создать новый экземпляр AccountXtra, когда у меня есть экземпляр Account?

Я пробовал:

//This doesn't work
AccountXtra newInstance = (AccountXtra)accountInstance;
//This also doesn't work
AccountXtra newInstance = new AccountXtra();
newInstance = accountInstance;

Ответы [ 5 ]

1 голос
/ 26 марта 2009

Вы не можете преобразовать базовый класс в подкласс. Другими словами, если объект имеет тип «Account», вы не можете привести его к «AccountXtra». Однако, если у вас есть класс «AccountXtra», поскольку он наследуется от «Account», вы можете затем преобразовать его в «Account».

Если у вас есть источник к существующему коду, вам нужно изменить место, где он вызывает конструктор "new Account ()", и изменить его на "new AccountXtra ()". Вам также следует заменить экземпляры класса «Account» на «AccountXtra»

Другая идея, которую вы можете попробовать, - это создать конструктор в AccountXtra (), который принимает аргумент типа «Account» и копирует всю информацию в новый экземпляр. Не совсем эффективный, но он достигнет желаемого эффекта.

public class AccountXtra : Account
{
    public AccountXtra(Account existingAccount) : base()
    {
        this.accountName = existingAccount.accountName;
        this.accountNumber = existingAccount.accountNumber;
        ...
    }
}
1 голос
/ 26 марта 2009

Теперь вам нужно создавать новые объекты класса производного , а не базы. Замените ваши старые звонки на new Account на new AccountXtra. Или вам нужен конструктор для AccountXtra, который принимает объект Account и создает новую версию его производного класса:

public AccountXtra(Account baseInstance) : this()
{
    this.Field1 = baseInstance.Field1;
    this.Field2 = baseInstance.Field2;
    ...
}

Объяснение: Нельзя приводить базовый класс к производному классу, если он не относится к типу производного класса. Это будет работать:

AccountXtra accountXtra = new AccountXtra();
Account xtraAsBase = (Account)accountXtra;
AccountXtra xtraCastBack = (AccountXtra)xtraCastAsBase;

Но это не будет:

Account Base = new Account();
AccountXtra baseAsDerived = (AccountXtra)Base;  //Cast base to derived class
1 голос
/ 26 марта 2009

НО, как мне создать новый экземпляр AccountXtra, когда у меня есть экземпляр Account?

Это идет не так, как надо - вам нужно создать объект AccountXtra, который затем можно будет везде обрабатывать как объект Account.

Кстати, если вы не уверены, какой тип объектов вы хотите создать в коде создания списка, вы можете прочитать о фабричных шаблонах .

Не стесняйтесь обновить свой вопрос с конкретными проблемами, которые у вас есть.

0 голосов
/ 26 марта 2009

Это было задумано как комментарий к предыдущему ответу, но я думаю, что это слишком долго.

Наличие дочернего класса с конструктором, который берет экземпляр родительского класса и копирует данные из него, является довольно распространенным стандартом. Один из способов минимизировать головную боль, которую это может вызвать с несколькими уровнями наследования и другими классами, состоит в создании защищенной функции, которая выполняет эту работу, в этом случае мы назовем ее Assign. Предположим, у нас есть три класса Person, Employee и Manager. Все они наследуют друг от друга в этом порядке.

public class Person
{
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    protected void Assign(Person otherPerson)
    {
        Name = otherPerson.Name;
    }
}

Теперь мы определяем Employee:

public class Employee : Person
{
    private int employeeID;

    public Employee() { }
    public Employee(Person newEmployee) : this()
    {
        base.Assign(newEmployee);
    }

    public int EmployeeID
    {
        get { return employeeID; }
        set { employeeID = value; }
    }

    protected new void Assign(Employee otherEmployee)
    {
        base.Assign(otherEmployee);

        EmployeeID = otherEmployee.EmployeeID;
    }
}

Затем мы следуем тому же примеру для менеджера:

public class Manager : Person
{
    private string department;

    public Manager() { }
    public Manager(Employee newManager) : this()
    {
        base.Assign(newManager);
    }

    public string Department
    {
        get { return department; }
        set { department = value; }
    }

    protected new void Assign(Manager otherManager)
    {
        base.Assign(otherManager);

        Department = otherManager.Department;
    }
}

Таким образом, метод Assign() в каждом классе объявил new, чтобы мы могли изменить сигнатуру и обеспечить функциональность поверхностного копирования для унаследованных классов.

Просто отметьте, что этот шаблон создает новый объект, который просто имеет те же данные, что и старый объект. Старый объект все еще существует, и существующие ссылки не будут указывать на ваш новый объект. На самом деле изменение ТИПА объекта не допускается.

0 голосов
/ 26 марта 2009

Вы можете абстрагировать его в общий абстрактный класс со всеми общими атрибутами:

public abstract class Account
{
   //all common members make them abstract
   public abstract int AccountId  { get; set; }
}

Тогда откуда ваша дополнительная и новая "базовая" учетная запись получена из этого общего класса учетной записи?

public class AccountBasic : Account
{ 
   public override int AccountId  { get; set; }
   //implement the rest
}

public class AccountExtra : Account
{
   public override int AccountId  { get; set; }
   //your extra details
   public int Period { get; set; }
   public int Visitors { get; set; }
   public string ContactName { get; set; }
}

Это позволяет вам иметь коллекцию, скажем: List allAccounts; где вы можете манипулировать общими атрибутами. Поддерживая экземпляры ваших специализированных классов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...