Matteo NNZ
Matteo NNZ

Reputation: 12645

Set property of derived class on base class' instance

I have a base class like this:

class Document {
    int number {get; set;}
    double sum {get; set;}
}

... and two derived classes:

class Bill : Document {
    double advance {get; set;}
}

class Quote : Document {
    double discount {get; set;}
}

At compile time, I know that I'll be dealing with an object of type Document. However, it's only at runtime that I know whether it will be a Bill or a Quote.

I need to perform specific operations depending on the type, e.g.:

if (myDoc.GetType() == typeof(Bill)) {
   myDoc.advance = 1000; //<-- can't find "advance"
}

.. but I can't compile like that as the properties of the derived class is not accessible from a base instance.

What is the proper way of doing that? Here's a fiddle to play around.

Upvotes: 0

Views: 72

Answers (3)

Todd Skelton
Todd Skelton

Reputation: 7239

Pattern matching is a good way to handle this if you are using C# 7.0+

if(myDoc is Bill bill)
{
    bill.Advance = 1000;
}
else if(myDoc is Quote quote)
{
    quote.Discount = 1000;
}

Upvotes: 2

Ahmed Sherien
Ahmed Sherien

Reputation: 313

You can simply cast it:

if (myDoc.GetType() == typeof(Bill))
{
    ((Bill)myDoc).advance = 1000;
}

Upvotes: 1

poke
poke

Reputation: 387507

myDoc.advance can only compile if the compiler can tell at compile time that myDoc is a Bill. Otherwise, myDoc is just a Document and that type does not have an advance member.

Doing a type check like that will not modify the static type of myDoc. Instead, you would have to type cast it into a Bill first:

Bill myBill = (Bill)myDoc;
myBill.advance = 1000;

Note that instead of using GetType() which checks the exact runtime type, you should be using the is operator to verify that myDoc is a Bill. You can even use the newer pattern matching syntax from C# to make this nicer:

if (myDoc is Bill myBill) {
    myBill.advance = 1000;
}

Finally, please note that the common convention is to write properties in C# in PascalCase (i.e. Advance, Number, Sum and Discount).

Also note that class members are private by default, so you still wouldn’t be able to access those properties. So you would have to add a public in front of the property definitions.

Upvotes: 3

Related Questions