Reputation: 2374
Let s say I got an abstract class A. There I got some inner classes like here:
public abstract class A
{
public InnerOne x;
public InnerTwo y;
public A(){
this.x = new InnerOne();
this.y = new InnerTwo();
}
public class InnerOne
{
public virtual double value(){
return 0;
}
}
public class InnerTwo
{
public virtual double value(){
return 0;
}
}
}
Then I got it's childrens like this one:
public class B: A
{
public B():base(){
}
public class InnerOne: A.InnerOne
{
public override virtual double value(){
return 100;
}
}
public class InnerTwo: A.InnerTwo
{
public override virtual double value(){
return 100;
}
}
}
So I was think that when I call B
constructor like that I will initialize x
and y
by creating it's inner classes instances. But actually it not works like that. When I call vaule
functions like here it returns zeros.
A newobject = new B();
var bv1 = B.x.value();
var bv2 = B.y.value();
Is there way to force B
class to initialize it's x
and y
fields by it's inner class objects (not with objects from parent abstract class) without re-writing it's constructor?
Upvotes: 2
Views: 98
Reputation: 273244
The 'inner class' aspect (embedded class definition) only distracts here, it plays no role.
And to answer the question: No, you cannot have 'virtual constructors' that work this way.
There are of course plenty of ways to get 100
instead of 0
as returnvalue but the question is too artificial to suggest one.
Upvotes: 1
Reputation: 1007
B.x
and B.y
are instances of A.InnerOne
and A.InnerTwo
, so you're seeing the value returned as 0 as these have nothing to do with B.InnerOne
or B.InnerTwo
.
The following B
constructor would assign x
and y
to instances of B.InnerOne
and B.InnerTwo
which would return 100.
public B(){
this.x = new InnerOne();
this.y = new InnerTwo();
}
If you wanted A
to work in the way you expect, you'd need to pass the inner types you wanted through from the B
constructor and create instances of them in the A
constructor, something like:
public B():base(typeof(InnerOne),typeof(InnerTwo)) { ... }
Using Activator.CreateInstance
will let you create these types within A
's constructor.
Enigmativity's generic solution is better if you always want A
used this way, alternatively this way allows you to have multiple constructors for A
so you could optionally pass in different types.
Upvotes: 1
Reputation: 117064
You can do it, but you must change the definition for class A
- and it gets super hairy.
Here's A
:
public abstract class A<I1, I2>
where I1 : A<I1, I2>.InnerOne, new()
where I2 : A<I1, I2>.InnerTwo, new()
{
public InnerOne x;
public InnerTwo y;
public A()
{
this.x = new I1();
this.y = new I2();
}
public class InnerOne
{
public virtual double value()
{
return 0;
}
}
public class InnerTwo
{
public virtual double value()
{
return 0;
}
}
}
And here's B
:
public class B: A<B.InnerOne, B.InnerTwo>
{
public B():base(){ }
public class InnerOne: A<InnerOne, InnerTwo>.InnerOne
{
public override double value()
{
return 100;
}
}
public class InnerTwo: A<InnerOne, InnerTwo>.InnerTwo
{
public override double value()
{
return 100;
}
}
}
Upvotes: 1
Reputation: 7903
Even though you have defined the classes inside A or B, they are still public and they are accessible outside A or B. Its no different from a class definied outside A or B.
Imagine the same code with the InnerOne
and InnerTwo
defined outside the class A and B. It will have the same above behavior. Your root of confusion is misunderstanding inner class usage.
Inorder to get 100, inside B you need to explicitly replace the instance of X and Y variables with an instance that overrides those values. Unless you do them you will not get 100.
public class B: A
{
public B():base(){
X = new OverridenInnerOne();
Y = new OverridenInnerTwo();
}
public class OverridenInnerOne: A.InnerOne
{
public override virtual double value(){
return 100;
}
}
public class OverridenInnerTwo: A.InnerTwo
{
public override virtual double value(){
return 100;
}
}
}
Upvotes: 2