C# method from derived class as delegate in base constructor - c#

Why is the following C# not legal? Does there exist a proper workaround?
public class Base
{
public Base(Func<double> func) { }
}
public class Derived : Base
{
public Derived() : base(() => Method()) <-- compiler: Cannot access non-static method 'Method' in static context
{
}
public double Method() { return 1.0; }
}

It's effectively referring to "this" within the arguments to the base constructor, which you can't do.
If your delegate really doesn't need access to this (which your sample doesn't) you can just make it static. You could also use a method group conversion to make it simpler:
public class Base
{
public Base(Func<double> func)
{
double result = func();
}
}
public class Derived : Base
{
public Derived() : base(Method)
{
}
public static double Method() { return 1.0; }
}
If you do need to use "this", you could:
Make it a virtual method instead of calling a delegate
Make it a static method which takes an appropriate instance, e.g.
public class Base
{
public Base(Func<Base, double> func)
{
double result = func(this);
}
}
public class Derived : Base
{
public Derived() : base(x => Method(x))
{
}
private static double Method(Base b)
{
// The documentation would state that the method would only be called
// from Base using "this" as the first argument
Derived d = (Derived) b;
}
}

Basically you get the compiler error because you are referencing the instance-method Method without an instance of your class Derived. When calling base, the constructor has not yet finished and you don't have an instance of your class yet. If you made Method static it would work just fine.

Another solution to this is simply to defer the initialization of the delegate to the derived class:
public class Base {
protected Func<double> DoubleFunc { get; set; }
protected Base() {
// defer initialization by not setting DoubleFunc
// or another possibility is to set it to a dummy function:
DoubleFunc = () => 0;
}
public Base(Func<double> func) {
DoubleFunc = func;
}
}
public class Derived : Base {
public Derived() {
DoubleFunc = Method;
}
public double Method() { return 1.0; }
}

Have you tried making Method() static as the compiler indicates? The problem is that an instance of Derived isn't available until after the constructor has returned so you can't call an instance method on it.

The "workaround" would be to make Method() a static method.
I can't explain the technical reasons why this does not work but essentially you're trying to call a method on an instance which does not yet exist. How could it possibly work?

Related

Why can't we call the constructor of the base class within the function body of the constructor of a subclass?

Why can't we call the constructor of the base class within the function body of the constructor of a subclass? For example,
public class Baseclass
{
public int X;
public Baseclass () { }
public Baseclass (int x) { this.X = x; }
}
why
public class Subclass : Baseclass
{
public Subclass (int x) : base (x) { }
}
instead of
public class Subclass : Baseclass
{
public Subclass (int x) : { base(x); }
}
or
public class Subclass : Baseclass
{
public Subclass (int x) : { base.Baseclass(x); }
}
My question is more from the perspective of the design of C#, or other similar OO languages such as C++ and Java, which all follow the same design.
Thanks.
Java does not actually allow what you're proposing - while in Java the call to super() is inside the subclass constructor's body it is a compile error if there are any statements before that call:
// This is Java
public class Subclass extends ParentClass {
public Subclass() {
String x = "foo";
super(); // <-- compile error
}
}
Anyway, the reason is because the runtime (and language specification) demands that the state of a superclass be fully-defined prior to any subclass instance code being executed.
A simple thought-experiment will demonstrate why:
// This is C#
public class ParentClass {
protected readonly Int32 x;
public ParentClass() {
this.x = 123;
}
}
public class Subclass : ParentClass {
// Using your proposed idea:
public Subclass() {
Int32 localX = base.x; // get the current value of `ParentClass.x`
base(); // call base constructor
}
}
In the example above, what is the value of localX?
The answer is "undefined" - and C# and the CLR (and Java) are designed to prevent undefined behaviour - whereas C++ is more forgiving, but that doesn't mean you should do it.
By requiring that all base classes are fully initialized before subclasses prevents an entire series of bugs relating to uninitialized data.
I will say one thing, however - there is no formal reason why we should not be able to execute static code prior to calling the parent constructor. We can actually do this in C# but we have to refactor code so it's a static function call via the parent class' constructor parameters, which isn't pretty - nor does it allow data to be passed directly back to the subclass constructor. So I wish we could do something like this:
public class ParentClass {
public ParentClass(String x, Int32 y) {
// ...
}
}
public class Subclass : ParentClass {
private static ComplexObject GetComplexObject() {
// ...
}
public Subclass() {
// All code before `base()` is executed in a static context:
ComplexObject cmplx = GetComplexObject();
base( cmplx.X, cmplx.Y );
}
}
Instead we currently need to do this:
public Subclass()
: base( GetComplexObject().X, GetComplexObject().Y ) {
}
Or use a static factory method with a private constructor:
private Subclass(String x, Int32 y) : base( x, y ) {
}
public static Subclass Create() {
ComplexObject cmplx = GetComplexObject();
return new Subclass( cmplx.X, cmplx.Y );
}
public class Subclass : Baseclass
{
public Subclass (int x) : base (x) { }
}
Yes this one is the correct answer. I've tried java but the syntax of almost c# codes are different. As soon as you call the base class with constructor on your subclass you need to follow the way you code it from the base class;
You may also try this upon instantiating
Baseclass base = new Baseclass(32);

Call base constructor with method as argument

I am a beginner in C# and cannot find out how to call a base constructor from within a subclass:
Base class:
public class LookupScript
{
protected Func<IEnumerable> getItems;
protected LookupScript()
{
//
}
public LookupScript(Func<IEnumerable> getItems) : this()
{
Check.NotNull(getItems, "getItems");
this.getItems = getItems;
}
My derived class:
public class PresenceLookup : LookupScript
{
public PresenceLookup() :base(??)
{
//
}
List<string> myMethod()
{
return null;
}
How can I pass myMethod to the base class?
Thank you
You can't, as myMethod is an instance method, and you can't access anything to do with the instance being created within the constructor initializer. This would work though:
public class PresenceLookup : LookupScript
{
public PresenceLookup() : base(MyMethod)
{
}
private static List<string> MyMethod()
{
return null;
}
}
That uses a method group conversion to create a Func<List<string>> that will call MyMethod.
Or if you don't need the method for anything else, just use a lambda expression:
public class PresenceLookup : LookupScript
{
public PresenceLookup() : base(() => null)
{
}
}

Dynamically instantiate class

I am trying to dynamically instantiate classes descendant of an abstract class, but the activator is forcing me to override the constructor to every descendant. Is there a way to avoid this?
P.S: I need to pass the parameters in the constructor, only there it can be Write, otherwise, it will always be read!
Is there a way to avoid this?
Short answer: Yes, when you define no constructor in your derived class, the (abstract) base class constructors are used. When you define one, you have to redefine all constructors.
Not without a workaround pattern.
EDIT: Sorry, I'm wrong that does only work for parameterless constructors.
How you can achive your goal,
is using a protected parameterless constructor and a static Create method:
public abstract class Duck {
private string _DucksParam0;
public string DucksParam0 {
get {
return _DucksParam0;
}
}
// Using protected, this constructor can only be used within the class instance
// or a within a derived class, also in static methods
protected Duck() { }
public static DuckT Create<DuckT>(string param0)
where DuckT : Duck
{
// Use the (implicit) parameterless constructor
DuckT theDuck = (DuckT)Activator.CreateInstance(typeof(DuckT));
// This is now your "real" constructor
theDuck._DucksParam0 = param0;
return theDuck;
}
}
public class Donald : Duck {
}
Usage (dotnetfiddle):
public class Program
{
public void Main()
{
Duck d = Duck.Create<Donald>("Hello World");
Console.WriteLine(d.DucksParam0);
}
}
Constructors are not inherited, so if you must instantiate a child object through a constructor with those parameters, then you need to write a new constructor in the child class that basically does base(p1, p2, ..., pn).
Looking at your code, seems that your constructors only assign/initialize fields, so there is no reason why you can't do that somewhere outside the constructor, as long as you control it appropriately. This might be a long shot, but I feel this is more what you want:
public abstract class Parent
{
protected bool foo
{
get;
private set; // just set the property setter as private
}
protected Parent() {
// protected so all instances are created through createAnotherX
// note that nothing is initialized here!
}
public abstract int Enter(); // To override in child classes
// Option 1: use generics
public static T createAnother1<T>(bool f) where T : Parent, new()
{
T p = new T();
p.foo = f;
return p;
}
// Option 2: use the runtime type
public static Parent createAnother2(Type t, bool f)
{
Parent p = Activator.CreateInstance(t) as Parent;
p.foo = f;
return p;
}
// Examples
public static void Main()
{
Parent p1 = Parent.createAnother1<Child>(true);
Parent p2 = Parent.createAnother2(typeof(Child), true);
}
}
// the child class only has to worry about overriding Enter()
public class Child : Parent
{
public override int Enter()
{
return 1;
}
}
Note that you must instantiate objects through the createAnotherX because the default constructor is protected. In addition, as per your comment, see that the property is defined so that only you can set values, which is what you tried to do in your code when explicitly ignoring the setter.

Inheriting Constructors?

Is it possible to inherit constructors, and if so, how?
I am trying to make a class that inherits a System class, and I want the constructors of it.
This is not possible in vanilla C#. Constructors can't be simply inheritted. They must be redefined on every level and then chained to the parent's version.
class Parent {
internal Parent(string str) { ... }
internal Parent(int i) { ... }
}
class Child : Parent {
internal Child(string str) : base(str) { ... }
internal Child(int i) : base(i) { ... }
}
Constructors don't 'inherit' the same way that methods do, but you do have the option of invoking base class constructors:
public DerivedClass(Foo foo) : base(foo)
All the other answers so far are correct. However, understand that you do not have to match the base class constructor's signature with the constructor you are defining:
public class Base
{
public Base(string theString) { ... }
}
public class Derived:Base
{
public Derived():base("defaultValue") //perfectly valid
{ ... }
public Derived(string theString)
:base(theString)
{ ... }
public Derived(string theString, Other otherInstance)
:base(theString) //also perfectly valid
{ ... }
}
... and in addition to invoking a parent class's constructor, you can also "overload" constructors within the same inheritance level, by using the this keyword:
public class FurtherDerived:Derived
{
public FurtherDerived(string theString, Other otherInstance)
:base(theString, otherInstance)
{ ... }
public FurtherDerived()
:this("defaultValue", new Other()) //invokes the above constructor
{ ... }
}
You can't inherit constructors; you have to call them explicitly (except for the default constructor, which is called, well, by default):
class A
{
public A (int i) { }
}
class B : A
{
public B (int i) : base (i) { }
}

Constructor chaining with "this"

Why does the first constructor in ClassA cause the compiler error 'cannot use "this" in member intializer'?
... or how can i get this to work?
Thanks
public sealed class ClassA : IMethodA
{
private readonly IMethodA _methodA;
public ClassA():this(this)
{}
public ClassA(IMethodA methodA)
{
_methodA = methodA;
}
public void Run(int i)
{
_methodA.MethodA(i);
}
public void MethodA(int i)
{
Console.WriteLine(i.ToString());
}
}
public interface IMethodA
{
void MethodA(int i);
}
You are allowed to use the this(...) syntax to invoke another constructor at the same level - however, you cannot use this (the current instance) in this context.
The easiest option here is to duplicate the assignment code (_methodA = methodA).
Another option might be null-coalescing:
public ClassA():this(null)
{}
public ClassA(IMethodA methodA)
{ // defaults to "this" if null
_methodA = methodA ?? this;
}
This is called out in section 10.11.1 of the C# spec
An instance constructor initializer
cannot access the instance being
created. Therefore it is a
compile-time error to reference this
in an argument expression of the
constructor initializer, as is it a
compile-time error for an argument
expression to reference any instance
member through a simple-name.
There is no way to get this to work with an instance constructor because this cannot be accessed. What you could do is make the constructor private, create an initialization method and a static constructor.
public sealed class ClassA : IMethodA {
private ClassA() { }
private void Initialize(IMethodA param) { ... }
public static ClassA Create() {
var v1 = new ClassA();
v1.Initialize(v1);
return v1;
}
public static ClassA Create(IMethodA param) {
var v1 = new ClassA();
v1.Initialize(param);
return v1;
}
}
You're trying to pass the object before it is constructed. Although the compiler could do something sensible in this case, in general that won't work.
Your actual example works if you just do this:
public ClassA()
{
_methodA = this;
}
But you probably want to share more logic, so just use a function.
public ClassA()
{
SetStuff();
_methodA = this;
}
public ClassA(IMethodA methodA)
{
SetStuff();
_methodA = methodA;
}
You can't use the this keyword when chaining constructors essentially because this refers to an object that hasn't been instantiated yet (creation of the object doesn't begin until some (the top-level or base) constructor block has been entered). Moreover, why exactly would you want to do this? It seems rather pointless when you have access to the this keyword everywhere.
I recommend simply using independent constructors as such:
public sealed class ClassA : IMethodA
{
private readonly IMethodA _methodA;
public ClassA()
{
_methodA = this;
}
public ClassA(IMethodA methodA)
{
_methodA = methodA;
}
}
Perhaps I misunderstand what you're trying to do, but hopefully that will solve the issue for you.

Categories