C# constructors annoy me!

  • Thread starter Thread starter Peter Morris [Droopy eyes software]
  • Start date Start date
P

Peter Morris [Droopy eyes software]

Look at these two classes

public class Test

{

public readonly string Name;

public Test(string name)

{

this.Name = name;

}

}

public class Test2 : Test

{

}



What annoys me is that trying to execute the following code gives me an
error that Test2 doesn't have a constructor that takes 1 argument.

new Test2("Hello");



It's pretty obvious that I want to use the inherited constructor, so why
wont C# use it?
 
change class Test2 to

public class Test2 : Test
{
public Test2(stirng name)
{
base(name);
}
}
 
It's pretty obvious that I want to use the inherited constructor, so why
wont C# use it?

Constructors aren't methods, so they don't need to conform to the LSP:
Barbara Liskov's Substitution Principle.

In Delphi, constructors are effectively methods of the metaclass, which
acts as a statically allocated factory object. It therefore makes sense
to inherit constructors, because they really are methods.

The Liskov Substitution Principle means that if you've got an instance
of a class C descended from a class B, you should be able to use an
instance of C wherever you use an instance of B. Since constructors
aren't methods, they don't need this substitutability support.

The fact that a descendant class can hide inherited constructors can
actually be seen as a feature. Subclasses are exactly that: subclasses,
more specific and less general than their base superclass. It stands to
reason that they may require more information to construct, and thus
require a constructor which takes more information.

If the constructors from the base class were inherited, then this would
break the descendant class's assumptions.

Alternatively, you can look at how things version. If you've written a
subclass C descended from your favourite component author's B class, you
may have requirements for your constructors that you've fulfilled by
overriding the base class's constructors. What if, in the next version,
B adds more constructors? It could break the assumptions of your class
C, because there would be a new way to construct it - that you didn't
have the chance to validate yourself.

-- Barry
 
change class Test2 to
public class Test2 : Test
{
public Test2(stirng name)
{
base(name);
}
}

Shouldn't that be

public class Test2 : Test
{
public Test2(string name): base(name)
{
}
}

?


Hans Kesting
 
Hi,
What annoys me is that trying to execute the following code gives me an
error that Test2 doesn't have a constructor that takes 1 argument.

new Test2("Hello");



It's pretty obvious that I want to use the inherited constructor, so why
wont C# use it?

It's incorrect. A Test2 knows how to build a Test instance, the opposite is
not true. Constructors are not inherited, and IIRC it has been like this
always ( somebody correct me if I'm wrong ).
 
Hi,


Dave said:
change class Test2 to

public class Test2 : Test
{
public Test2(stirng name)
{
base(name);
}
}


This is wrong, it should be public Test2(string mane):base(name){}
 
Peter said:
It's pretty obvious that I want to use the inherited constructor, so why
wont C# use it?

Inherited constructors would means that, in general, a specialization of
a class could be constructed with the same arguments as the super-class.
For many specializations this does not make sense.

It would be nice with another way to declare a constructor which would
invoke base() with the same arguments. Lots of other things would be
nice to have too.

The, rather simple -- if slightly verbose, solution is to simply copy
the constructor declaration and invoke base(args) yourself.
 
In Delphi, constructors are effectively methods of the metaclass, which
acts as a statically allocated factory object. It therefore makes sense
to inherit constructors, because they really are methods.

Yes I head that ctors in delphi can actually return null :)
If the constructors from the base class were inherited, then this would
break the descendant class's assumptions.

Alternatively, you can look at how things version. If you've written a
subclass C descended from your favourite component author's B class, you
may have requirements for your constructors that you've fulfilled by
overriding the base class's constructors. What if, in the next version,
B adds more constructors? It could break the assumptions of your class
C, because there would be a new way to construct it - that you didn't
have the chance to validate yourself.

Does delphi suffer from that problem? Would the OP's program work with
delphi?
 
"cody" <[email protected]> a écrit dans le message de eNWx5%[email protected]...

| Yes I head that ctors in delphi can actually return null :)

Only if an exception occurs in the constructor.

| Does delphi suffer from that problem? Would the OP's program work with
| delphi?

Peter is an old hand at Delphi, just like me; his program would use the the
fact that all constructors in base classes are visible throughout the
hierarchy, whether they be virtual or not.

This visibility can, IMO, cause more problems than it cures. TObject is the
base class of all reference types, sort of analagous to System.Object but
without the reflection metadata but also with a ClassType() method that
returns an instance of TClass, a sort of metaclass, sort of analagous to
System.Type but with a Create() method which is effectively a constructor
for TObject.

This arrangement allows you to do some cool things without having to create
class factories :

TFruit = class
...
public
constructor Create; virtual; abstract
end;

TApple = class(TFruit)
...
public
constructor Create; override;
end;

TOrange = class(TFruit)
...
public
constructor Create; override;
end;

TFruitClass = class of TFruit;

var
fruitCreator: TFruitClass;
fruit: TFruit;
begin
fruitCreator := TApple;

fruit := fruitCreator.Create; //creates an Apple

fruitCreator := TOrange;

fruit := fruitCreator.Create; // creates an Orange

...
end;

Any pattern of constructor, parameterised or not, can be declared in the
base class as virtual and/or abstract and overridden in derived classes.

It is quite easy and feasible to create your own metaclasses in C# and have
virtual/abstract methods called Create(...) which then give the same idea,
essentially acting as class factories rather than the true metaclass found
in Delphi.

One major disadvantage of Delphi for Win32 is that the TObject Create
default constructor is public and not hideable, therefore you can always
circumvent a protected or private constructor such as you might use in a
Singleton class to ensure only one instance.

Joanna
 
cody said:
Yes I head that ctors in delphi can actually return null :)

The short answer is no, constructors can't return null (or nil as it's
called in Delphi).

There is a way to customize the memory allocation mechanism such that a
null pointer would be returned, in a similar way to the way you can
override operator new in C++, but it wouldn't be very useful because the
next step in the Delphi object construction sequence is to fill the
contents of the allocated memory with zeros, and that would cause an
access violation.
Does delphi suffer from that problem? Would the OP's program work with
delphi?

The OP's program would indeed work, and Delphi does have this problem.
On the other hand, it's more of a theoretical problem than a real
problem.

An advantage of Delphi's approach is that you can create virtual
constructors, and pass around metaclasses which will construct the
correct descendant when the constructor is called.

The main constructor for most components in Delphi is virtual, and as a
result of this design all the other constructors usually call the
virtual one to get correct overridden behaviour. This seems to lead to
less of a reliance on constructor parameters in class libraries designed
for Delphi, and more of a reliance on properties.

-- Barry
 
Helge said:
Inherited constructors would means that, in general, a specialization of
a class could be constructed with the same arguments as the super-class.
For many specializations this does not make sense.

Exactly.

Perhaps an example to visualize this. :)
First two classes:


public class Person {

private string name;

public Person(string name) {
this.name = name;
}

public string Name { get { return this.name; } }

}

public class Emplyee : Person {

private string title;

public Employee(string name, string title) : base(name) {
this.title = title;
}

public string Title { get { return this.title; } }

}


Now, if constructors were inherited, you could write the following code,
and it would cause a null reference exception:


Employee nisse = new Employee("Nisse Hult"); // uses Person constructor

string title = nisse.Title; // argh!
 
"Barry Kelly" <[email protected]> a écrit dans le message de (e-mail address removed)...

| If an exception occurs, nothing gets returned - the exception is
| propagated!
|
| Sorry, Joanna ;)

Ok, so it's a few months since I last used the Delphi language :-)

But the receiving reference gets set to nil... I think :-}

Joanna
 
Now, if constructors were inherited, you could write the following code,
and it would cause a null reference exception:


Employee nisse = new Employee("Nisse Hult"); // uses Person constructor

string title = nisse.Title; // argh!

Ehm... Of course it doesn't cause an exception, but the title string
will be null.
 
Now, if constructors were inherited, you could write the following code,
and it would cause a null reference exception:

But in your example you *are* creating a constructor. What I would like is
implicit constructors, so if I don't add an explicit one then the class
inherits them because it is obvious that no extra work is needed to
construct an instance.
 
But there is already a behaviour defined for that case. If you don't
specify any constructor, an empty constructor is created for you, that
calls the empty constructor in the base class:

public class B : A {
}

is the same as:

public class B : A {
public B() : base() {}
}
 
But there is already a behaviour defined for that case.

Only on condition that you have no parameters. My classes all take a single
parameter.
 
Peter said:
Only on condition that you have no parameters. My classes all take a single
parameter.

No, the behaviour is defined regardless of what constructors the base
class has. ;)

If the constructors would be inherited, that would mean that adding a
constructor to a base class would also magically add a constructor to
all the classes that inherit the base class. In most cases that would
mean that all the inheriting classes would get a constructor that
doesn't properly initialize the object.
 
Peter Morris said:
Only on condition that you have no parameters. My classes all take a single
parameter.

In that case, what would you expect to happen if classes inherited
constructors and someone used the parameterless contructor inherited
(directly or indirectly) from System.Object?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top