I have a class Foo
that has a field _customObject
that must be initialized. I also have a class Bar
that inherits from Foo
:
public abstract class Foo
{
protected CustomObject _customObject;
public Foo()
{
// Do stuff
}
// Other methods that use _customObject
}
public class Bar : Foo
{
// Constructor and other methods
}
I can not initialize the object _customObject
in Foo
because every child inherited contains a different child of CustomObject
, so it must be initialized in every child class:
public class Bar : Foo
{
public Bar()
{
_customObject = new CustomObjectInherited1();
}
}
public class Baz : Foo
{
public Baz()
{
_customObject = new CustomObjectInherited2();
}
}
Other people are going to implement new classes that inherit from Foo
, so I was wondering if there is a way that an error in build time is shown, similar to when an abstract method is not implemented. If CustomObject
is not initialized, a NullReferenceException
will be thrown due to the use of the _customObject
variable, ending in an application crash.
You can add a parameter to your Foo
constructor:
public abstract class Foo
{
protected CustomObject _customObject;
public Foo(CustomObject obj)
{
// Do stuff
_customObject = obj;
}
// Other methods that use _customObject
}
Your derived classes will then be forced to call it, passing in a CustomObject
, or something derived from it:
public class Bar : Foo
{
public Bar():base(new CustomObjectInherited1())
{
}
}
Not calling the base constructor will result in a compile time error. This doesn't entirely protect you, as someone could still pass null
to the base constructor, but at least they'll have an explanation as to why they're getting a NullReferenceError
at runtime.
You can force it by creating a abstract method which requires child classes to override it.
public abstract class Foo
{
protected abstract CustomObject CreateCustomObject();
}
public class Bar : Foo
{
protected override CustomObject CreateCustomObject()
{
return new BarCustomObject();
}
}
Or my favorite solution: Enforce it by generic constraints.
public abstract class Foo<T> : where T : CustomObject, new()
{
protected T _customObject;
public Foo()
{
this.CustomObject = new T();
}
}
public class Bar : Foo<BarCustomObject>
{
}
The answer provided by "James Thorpe" is correct (I've upvoted it already), but I wanted to share just another option here: You could mark your class as abstract and introduce an abstract property instead of the "_customObject" field. That way, at least the first initializer will be forced to implement it. The downside is that you'll loose the enforcement on subsequent level subclasses:
public abstract class Foo
{
protected abstract CustomObject CustomObject {get; }
public Foo()
{
// Do stuff
}
// Other methods that use _customObject
}
public class Bar : Foo
{
// Constructor and other methods
protected override CustomObject CustomObject
{
get { return "X"; }
}
}
Also, with the first solution it's possible to validate the passed in value in the constructor - though, that'll be a runtime validation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With