tags:

views:

142

answers:

5

I wish to extend a base class in C# with some additional functionality. I have existing code which returns an array of the base class objects (Account) which I need to convert into the extended version.

So I have the extended version:

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

All is good.

BUT how do I create a new instance of AccountXtra when I have a instance of Account?

I have tried:

//This doesn't work
AccountXtra newInstance = (AccountXtra)accountInstance;
//This also doesn't work
AccountXtra newInstance = new AccountXtra();
newInstance = accountInstance;
+1  A: 

BUT how do I create a new instance of AccountXtra when I have a instance of Account?

That's going the wrong way - you need to have created the AccountXtra object which can then be treated everywhere as an Account object.

By the way, if you're not sure what type of objects you'll want to create in your list-creation code, you might want to read about factory patterns.

Feel free to update your question with specific problems you're having.

overslacked
+1  A: 

You cannot convert a base class into a subclass. In order words, if the object is of type "Account", you cannot cast it to "AccountXtra". However, if you have an "AccountXtra" class, since it inherits from "Account", you can then cast it to Account.

If you have the source to your existing code, you need to change where it calls the "new Account()" constructor and change it to "new AccountXtra()". You should also replace the instances of the "Account" class to "AccountXtra"

Another idea you can try is to create a constructor in AccountXtra() which takes an argument of type "Account" and copies all of the information into the new instance. Not exactly efficient, but it will achieve the effect you're looking for.

public class AccountXtra : Account
{
    public AccountXtra(Account existingAccount) : base()
    {
        this.accountName = existingAccount.accountName;
        this.accountNumber = existingAccount.accountNumber;
        ...
    }
}
Jesse Weigert
Thanks for the answer. I had an assumption about class inheritance which has been clearly wrong (wrong in the sense of not being reality anyway!)
Harry
I think you might "subclass", not "superclass". And also, instance thereof.
recursive
no problem. I added another option for you to try if you don't have access to the code which is generating these account objects.
Jesse Weigert
recursive: you're right.. I'm fixing it now.
Jesse Weigert
+1  A: 

You need to be generating new objects of the derived class now, not the base. Replace your old calls to new Account with new AccountXtra. Or, you need a constructor for AccountXtra that takes an Account object and makes a new derived-class version of it:

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


Explanation: You can't cast a base class to a derived class unless it is of the derived class type. This will work:

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

But this will not:

Account Base = new Account();
AccountXtra baseAsDerived = (AccountXtra)Base;  //Cast base to derived class
lc
"this.Field1 = baseInstance.Field1" this is what i was hoping to avoid.The alternative is to wrap the base class and expose it as a property. This seems like the lesser evil
Harry
In that case I wouldn't use inheritance at all, I would make a new class that contains an instance of the base class. But if you do have access to the code that creates your Account objects, simply change those to create AccountXtra objects instead. Then you're free to do whatever you want.
lc
A: 

You may want to abstract it out into a common Abstract Class with all the common attributes:

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

Then have your extra and a new "basic" account derive from that generic Account class?

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

This lets you have a collection say: List allAccounts; where you can manipulate the common attributes. While maintaining instances of your specialized classes.

Nick Josevski
That would be the decorator pattern. Seems like over kill in this situation.
Harry
A: 

This was intended as a comment on a previous answer, but I guess it's too long.

Having a child class with a constructor that takes an instance of a parent class and copies data from it is a fairly widespread standard. One way to minimize the headache that this can cause with multiple levels of inheritance and other classes is to create a protected function that does this work, in this instance we'll call it Assign. Consider that we have three classes, Person, Employee, and Manager. They each inherit from the other in that order.

public class Person
{
    private string name;

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

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

Now we define 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;
    }
}

Then we follow the same example for Manager:

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

So the Assign() method in each class declared new so that we can change the signature, and is there to provide shallow copy functionality to inherited classes.

Just note that this pattern creates a NEW object that just has the same data as the old object. The old object still exists and existing references won't point to your new object. Actually changing an object's TYPE is not allowed.

Adam Robinson
Ah yes the simplefactory pattern
Harry