How to have a sealed constructor? - c#

I have a baseclass which has public contructors.
The baseclass is not sealed and is not abstract.
There is one constructor which I desire to be sealed. Is this possible?
My current attempt results in syntax error saying the constructor cannot be sealed.
public sealed MyBase(string someParam)
Additional:
I wish to be able to instantiate the base class directly and have access to the sealed constructor. Derived classes cannot use that constructor via the derived constructors.
E.g.
public MyDerived() : base(string cant_access_my_sealed_constructor)

You can't do that. If the constructor is public, you can call it from constructors of derived classes. But you can do something close – you can have a private constructor and a public static method that calls it:
class MyBase
{
private MyBase(string someParam)
{
// some code
}
public static MyBase Create(string someParam)
{
return new MyBase(someParam);
}
protected MyBase() // or some other protected or public constructor
{ }
}
class MyDerived : MyBase
{
public MyDerived()
: base("foo") // won't compile, as requested
{ }
}

All constructors are "sealed" in that they cannot be "overridden." They can only be called from the constructor in a child class.
If you are hoping to prevent child classes from having a constructor with the same signature, that cannot be done.
Based on the additional information you added to the post, it sounds like what you want to do is make your constructor private, as Kyle suggested. This will prevent the child class from calling the constructor, but it won't prevent it from taking the same types of arguments:
public class Foo
{
private Foo(string s){
}
// Allowed
public Foo() : this("hello") {
}
}
public class Bar : Foo
{
// Allowed
public Bar(string s) : base(){
}
// Not allowed
public Bar(string s) : base(s){
}
}

If you want to prevent the constructor from being called by inherited classes, just mark it private.
Constructors aren't inherited by a child class, you have to explicitly call a base constructor if desired.
This code will call the base class' no-parameter constuctor when an instance of the child class is instantiated. Without it, the base class' constructor won't be called when creating a new instance of the child class.
public class A
{
public A()
{
}
}
public class B : A
{
public B()
: base()
{
}
}

Related

Forcing a derived class to have a constructor with a signature

How do I force all derived classes of an interface to have a constructor with a signature? This doesn't work:
public interface Constructor<T> where T : Constructor<T>, new()
{
Constructor(T);
}
public interface IParameters
{
}
public interface IRule : Constructor<IParameters>
{
//IRule (IParameters); must exist
}
You can't, not via an interface. But you can sort of get at it with an abstract class. Similar to what the accepted answer here describes, try:
public abstract class MustInitialize<T>
{
public MustInitialize(T parameters)
{
}
}
public class Rule : MustInitialize<IParameters>, IRule
{
IParameters _parameters;
public Rule(IParameters parameters)
: base (parameters)
{
_parameters= parameters;
}
}
You can't force a specific constructor signature.
Even with an abstract class as demonstrated in Mark's answer, you can only force the constructor of the abstract class, but nothing is stopping the author of the derived class to do something like this:
public class Rule : MustInitialize<IParameters>, IRule
{
public Rule()
: base (new Parameters())
{
// Assuming Parameters is a class that implements the IParameters interface
}
}
However, you can force dependency injection by using method (setter) injection:
public interface IMethodInjection<T>
{
void Method(T injected);
}
I think you can design your base class like the following example:
public abstract class MyBase
{
private MyBase()
{
}
public MyBase(string a)
{
}
}
public class MyDerived : MyBase
{
public MyDerived(string a) : base(a)
{
}
}
You can even delete the private constructor if its not needed

Can a method in a generic abstract base class "know" the most-derived class of its instance?

I'm trying to figure out if this is possible:
public abstract class A<T>
{
public void MyFunc() { ... }
}
public MyClass : A<string>
{
}
Is there a way for MyFunc to know that it has been instanced in a clas of type MyClass ?
I think I need to clarify the question some more:
I have a generic abstract class that contains some core functionality accessed through a singleton.
The user is building a derived class to extend functionalities but the class is not instantiated through a new, but rather by the singleton, contained in the A class once it is accessed.
So, you could see the flow as such:
In the beginning, there is the abstract A<T>
The user creates MyClass : A<string>
The user now accesses: MyClass.MyFunc()
The singleton in MyFunc is then creating the instance
The singleton code is as follows:
public abstract class Singleton<T> where T : class
{
private static readonly Lazy<T> _Instance = new Lazy<T>(CreateInstanceOfT);
protected static T Instance => _Instance.Value;
private static T CreateInstanceOfT()
{
return Activator.CreateInstance(typeof(T), true) as T;
}
}
so:
class A<T>
is really:
class A<T> : Singleton<A>
but what I really need is to, somehow, make it like
Singleton<MyClass>
or whatever class is deriving from
A<T>
I hope this clarifies the question.
Yes, you could do something like:
public abstract class A<T>
{
public void MyFunc()
{
if(this.GetType() == typeof(MyClass))
{
// do your magic
}
}
}
public class MyClass : A<string>
{
}
but why?
Seems to me, if I read your question right, that if the instance of A needs to have MyFunc act differently when it is a MyClass, then MyFunc should be virtual, and overridden in MyClass.
public abstract class A<T>
{
public virtual void MyFunc() { ... }
}
public MyClass : A<string>
{
public override void MyFunc() { ... }
}

Issue when inheriting abstract generic class

I have an abstract generic class:
public abstract class A<T> where T : class, new()
{
public A (IEnumerable<T>_Data)
{
this.Data = _Data;
}
private IEnumerable<T>_data;
public IEnumerable<T> Data
{
get { return _data; }
set { _data = value;}
}
}
Then when I inherit from that class:
public class B<T> : A<T> where T : class, new()
{
}
I get an error:
There is not argument that corresponds to the required formal parameter '_Data' of 'A.A(IEnumerable)'
in the 'B' class.
You need to inherit A<T>, not A:
public class B<T> : A<T> where T : class, new(){
}
Furthermore public A(_Data) is not constructor, which I assume you wanted. You need public A<T>(IEnumerable<T> _Data)instead.
Last but not least you have to create a constructor for B that can invoke any of those from A. So either define a parameterless constructor in A or one in B with IEnumerable<T> as argument:
public class B<T> : A<T> where T : class, new()
{
public B<T>(IEnumerable<T> data) : base(data) { ... }
}
As it says in the error, it cannot create the base class because you did not provide the correct constructor in B. change it to this if you want to pass any args
public class B<T> : A<T> where T : class, new(){
public B(IEnumerable<T> data):base(data) {
}
}
Otherwise, new your data in the constructor and and pass it to base.
Either provide a public parameterless constructor on your base class or as others suggested make a call to your base class constructor by passing IEnumerable<T> from the derived class

Error on constructor in derived class

I have a parent class
abstract class ClassPlugin
{
public ClassPlugin(eGuiType _guyType)
{
GuiType = _guyType;
}
public eGuiType GuiType;
public void Action() { }
}
I want all derived classes to implement the Action member and to define the guyType field.
To do that I have put it in the constructor, this is the only way that comes to mind.
Therefore an abstract class can be:
class ClassStartWF: ClassPlugin
{
public ClassStartWF(eGuiType _guyType)
{
GuiType = _guyType;
}
public void Action()
{
MessageBox.Show(GetType().Name);
}
}
the problem is that I get the error:
Severity Code Description Project File Line Suppression State
Error CS7036 There is no argument given that corresponds to the
required formal parameter '_guyType' of
'MainWindow.ClassPlugin.ClassPlugin(MainWindow.eGuiType)'
You should call the base class constructor in derived class constructor. Since you have create a constructor then compiler will not generate default constructor for your classes.
public ClassStartWF(eGuiType _guyType)
: base(_guyType)
{
// GuiType = _guyType; //this is not needed since the value is assigned in the base class constructor
}
Two problems...
First, you need to call the base class constructor from the derived type, as the base has no default constructor:
public ClassStartWF(eGuiType _guyType) : base(_guyType)
{
}
Since the base class takes care of setting the field you don't need to do it.
Secondly, you should make Action abstract in the base class and then override it in the derived class:
abstract class ClassPlugin
{
public abstract void Action();
}
class ClassStartWF: ClassPlugin
{
public ClassStartWF(eGuiType _guyType)
{
GuiType = _guyType;
}
public override void Action()
{
MessageBox.Show(GetType().Name);
}
}
At the moment you calls to Action won't dispatch to the derived instances when called through a base reference.
Also, rather than make GuiType a public variable you'd be better off making it a property:
public eGuiType GuiType{get; set;}
This will give you some control over the value. Also, you might want to consider making the setter private if it should only ever be set during construction.

An inherited singleton class from a base class that takes parameters in its constructor?

public class BaseFoo
{
private string param;
public BaseFoo(string param)
{
this.param = param;
}
}
public sealed class SingletonFoo : BaseFoo
{
static readonly SingletonFoo instance = new SingletonFoo();
static SingletonFoo()
{
}
public static SingletonFoo Instance
{
get
{
return instance;
}
}
}
Is this kind of inheritance possible, where the base class requires a constructor with parameters? (The above code won't obviously compile because no parameter is passed to the base class.)
If yes, how is it accomplished?
You need to make an instance constructor, and then refer to it:
public sealed class SingletonFoo : BaseFoo
{
static readonly SingletonFoo instance = new SingletonFoo("Some Value");
static SingletonFoo()
{
}
private SingletonFoo(string value) : base(value)
{
}
// ...
This will let you declare the parameter in the inline constructor, and call it down the chain.
You use the 'base' keyword:
public SingletonFoo (string param) : base(param)
{
}
I'm pretty sure a 'singleton' deriving from a non-singleton base class completely invalidates the entire concept of the pattern, which is often used inappropriately to start with.
Static constructors do not take parameters, so the only way to pass them to the base class would be via constructor-chaining but I'm pretty sure you can't invoke an instance constructor from a static constructor...
What exactly are you trying to do here?

Categories