Reputation: 33
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
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
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
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
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