nsmanners
nsmanners

Reputation: 33

Using Derived Class In a Base Method

I want to reuse code in my BaseRecordProcessor class as much as possible, but I am having trouble figuring out how to use derived classes within the base class.

An example of what I am trying to do is below.

public class BaseRecordProcessor
{
    public void ProcessRecord()
    {
        List<BaseRecord> records = GetRecordValues();

        foreach (BaseRecord record in records)
        {
            DoStuff(record);
        }
    }

    public virtual DoStuff (BaseRecord record)
    {
        // do stuff
    }
}

public class DerivedRecordProcessor : BaseRecordProcessor
{
    public override DoStuff (DerivedRecordOne record)
    {
        // do stuff
    }
}

Notice the DoStuff method in the DerivedRecordProcessor class will be passing a DerivedRecordOne class to the method while the virtual method in the BaseRecordProcessor class is passing in the BaseRecord class. Is there a way to do this?

Here are the record classes:

public class BaseRecord
{
    // hold record information
}

public class DerivedRecordOne : BaseRecord
{
    // hold additional record information
}

public class DerivedRecordTwo : BaseRecord
{
    // hold more record information
}

Upvotes: 1

Views: 111

Answers (4)

Tim Copenhaver
Tim Copenhaver

Reputation: 3302

You can accomplish this using generics. Something like this:

public class BaseRecordProcessor<T> where T : BaseRecord
{
    public virtual void DoStuff(T myObj)
    {
    }
}

public class DerivedRecordProcessor : BaseRecordProcessor<DerivedRecordOne>
{
    public override void DoStuff(DerivedRecordOne derived)
    {
    }
}

EDIT: Scratch the original example, I didn't read the question well enough. The same idea works, but I updated the example to match what you were actually doing.

Upvotes: 2

Gustavo Mori
Gustavo Mori

Reputation: 8386

You need to use a record interface. Let's add a method to this interface so we can see it in action later.

public interface IRecord
{
    void DisplayName();
}

Note that all your record types need to implement this interface.

public class BaseRecord : IRecord
{
    public void DisplayName()
    {
        Console.WriteLine("BaseRecord");
    }
}

public class DerivedRecordOne : BaseRecord, IRecord
{
    public void DisplayName()
    {
        Console.WriteLine("DerivedRecordOne");
    }
}

public class DerivedRecordTwo : BaseRecord, IRecord
{
    public void DisplayName()
    {
        Console.WriteLine("DerivedRecordTwo");
    }
}

We can now tweak the processing types to take interfaces, rather than specific types.

public class BaseRecordProcessor
{
    public void ProcessRecords()
    {
        foreach (var record in GetRecordValues())
        {
            DoStuff(record);
        }
    }

    public virtual void DoStuff(IRecord record)
    {
        // do stuff
    }

    private List<IRecord> GetRecordValues()
    {
        var records = new List<IRecord>();

        records.Add(new BaseRecord());
        records.Add(new DerivedRecordOne());
        records.Add(new DerivedRecordTwo());

        return records;
    }
}

public class DerivedRecordProcessor : BaseRecordProcessor
{
    public override void DoStuff(IRecord record)
    {
        record.DisplayName();
    }
}

If you now instantiate a record processor, and run it:

DerivedRecordProcessor processor = new DerivedRecordProcessor();
processor.ProcessRecords();

You will see the expected outcome:

BaseRecord

DerivedRecordOne

DerivedRecordTwo

I'll leave it to you to investigate why each record type needs to implement IRecord :P

Upvotes: 0

StarPilot
StarPilot

Reputation: 2272

Small change to your posted code:

public class DerivedRecordProcessor : BaseRecordProcessor
{
    public override DoStuff (BaseRecord record)
    {
        if( record is DerivedRecordOne ) 
        {
            // Do DerivedRecordOne stuff here
        } 
        else 
        {
           // do base stuff
           base.DoStuff( record );
        }
    }
}

This is polymorphism and using C#'s object type detection to your advantage. To do that, we change DerivedRecordProcessor.DoStuff() to taking a parameter of BaseRecord. Then we test the actual passed parameter to see if it is something this class should handle specifically, or if it is something the base class's method should handle.

Note, if you want, you can even cast record to DerivedRecordProcessor, and use it for the if test (so you don't have to cast it later). That gives us:

public class DerivedRecordProcessor : BaseRecordProcessor
{
    public override DoStuff (BaseRecord record)
    {
        DerivedRecordOne derivedRecordOne = record as DerivedRecordOne;
        if( null != derivedRecordOne ) 
        {
            // Do DerivedRecordOne stuff here using local variable derivedRecordOne 
        } 
        else 
        {
           // do base stuff
           base.DoStuff( record );
        }
    }
}

Upvotes: 0

M.Azad
M.Azad

Reputation: 3763

you can add an interface as IRecord and add IRocord as parameter in your method like

public Interface IRecord
{
    ...
}
public class BaseRecord:IRecord
{
    //hold record information
}

public class DerivedRecordOne : BaseRecord,IRecord
{
    //hold additional record information
}

public class BaseRecordProcessor
{

    public virtual DoStuff(IRecord record)
    {
        //do stuff
    }
}
public class DerivedRecordProcessor : BaseRecordProcessor
{
    public override DoStuff(IRecord record)
    {
        //do stuff
    }
}

Upvotes: 0

Related Questions