Reputation: 47
Apologies if this is a commonly asked question, but I have spend quite a while googling for the answer and could not find definitive answer.
I have an abstract class that contains fields that are (definitions of) other abstract classes . Those are then used for concrete implementations of properties. However when I want to initialize implementation of that abstract class I would like those fields to be populated with particular implementations of the fields. This actually sounds confusing even for myself, so here is the example.
// My main abstract class
public abstract class Log
{
public virtual bool AppendLog
{
set { _logWriter.Append = value; }
}
internal LogWriter _logWriter; //LogWriter is another abstract class
public abstract void AddEntry(string input);
}
// Implementation of abstract class
public class SyncLog : Log
{
public SyncLog
{
// Now I want to initialize LogWriter abstract class in parent with
// It's actual implementation SyncLogWriter : LogWriter
_logWriter = new SyncLogWriter();
}
public override void AddEntry(string input)
{
content.AddEntry(input);
_logWriter.Write("Hello");
}
}
While this technically complies and even works, there is a problem. When using the _logWriter I can only access the methods and properties declared in abstract class LogWriter, but not ones that are additionally implemented in it's child (SyncLogWriter). While technically it makes sense I wonder if there is any way to do the similar approach, but making all the additional stuff available in SyncLogWriter be available?
Upvotes: 2
Views: 134
Reputation: 6975
To my mind, a cleaner solution than the other two answers would be to use generics, as so:
public abstract class Log<TLogWriter> where TLogWriter : LogWriter
{
public virtual bool AppendLog
{
set { _logWriter.Append = value; }
}
internal TLogWriter _logWriter;
public abstract void AddEntry(string input);
}
public class SyncLog : Log<SyncLogWriter>
{
public SyncLog
{
_logWriter = new SyncLogWriter();
}
public override void AddEntry(string input)
{
content.AddEntry(input);
_logWriter.Write("Hello");
}
}
This removes the need for duplicating fields, or casting
Upvotes: 1
Reputation: 73482
You can create a private readonly property of type SyncLogWriter
which actually points to _logWriter
.
public class SyncLog : Log
{
public SyncLog
{
_logWriter = new SyncLogWriter();
}
private SyncLogWriter LogWriter
{
get { return (SyncLogWriter)_logWriter; }
}
public override void AddEntry(string input)
{
content.AddEntry(input);
_logWriter.Write("Hello");
}
private void DoSomething()
{
LogWriter.SomeSyncLogWriterMethod();
}
}
Upvotes: 1
Reputation: 1628
Use an additional member _syncLogWriter
on the inherited class SyncLog
.
Also it is even better to initialize your _logWriter
member for the base class through the constructor and make it private.
// My main abstract class
public abstract class Log
{
protected Log(LogWriter logWriter)
{
_logWriter = logWriter;
}
public virtual bool AppendLog
{
set { _logWriter.Append = value; }
}
private LogWriter _logWriter; //LogWriter is another abstract class
public abstract void AddEntry(string input);
}
// Implementation of abstract class
public class SyncLog : Log
{
private SyncLogWriter _syncLogWriter
public SyncLog() : this(new SyncLogWriter()) { }
private SyncLog(SyncLogWriter logWriter) : base(logWriter)
{
_syncLogWriter = logWriter;
}
public override void AddEntry(string input)
{
content.AddEntry(input);
_syncLogWriter.Write("Hello");
}
}
Upvotes: 1