2009-03-26 4 views
2

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

Поэтому у меня есть расширенная версия:

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

Все это хорошо.

BUT Как создать новый экземпляр AccountXtra, когда у меня есть экземпляр учетной записи?

Я пробовал:

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

ответ

1

Вы должны генерировать новые объекты класса полученные сейчас, а не базу. Замените старые звонки на 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 
+0

«this.Field1 = baseInstance.Field1» это то, чего я надеялся избежать. Альтернатива заключается в том, чтобы обернуть базовый класс и разоблачить его как свойство. Это похоже на меньшее зло –

+0

В этом случае я бы не использовал наследование вообще, я бы сделал новый класс, содержащий экземпляр базового класса. Но если у вас есть доступ к коду, который создает объекты вашей учетной записи, просто измените их для создания объектов AccountXtra. Тогда вы можете делать все, что захотите. –

1

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

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

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

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

1

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

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

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

public class AccountXtra : Account 
{ 
    public AccountXtra(Account existingAccount) : base() 
    { 
     this.accountName = existingAccount.accountName; 
     this.accountNumber = existingAccount.accountNumber; 
     ... 
    } 
} 
+0

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

+0

Я думаю, что вы можете «подклассы», а не «суперкласс». А также, пример этого. – recursive

+0

без проблем. Я добавил еще один вариант, чтобы вы могли попробовать, если у вас нет доступа к коду, который генерирует эти объекты учетной записи. –

0

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

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

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

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; } 
} 

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

+0

Это будет узор декоратора. Похоже на убийство в этой ситуации. –

0

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

Наличие дочернего класса с конструктором, который принимает экземпляр родительского класса и копирует данные из него, является довольно распространенным стандартом. Один из способов свести к минимуму головную боль, которая может привести к нескольким уровням наследования и другим классам, - создать защищенную функцию, которая выполняет эту работу, в этом случае мы будем называть ее 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 так, что мы можем изменить подписи, и есть возможность предоставлять неглубокие функции копирования унаследованным классам.

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

+0

А да простую картину –

Смежные вопросы