.NET Forum / Languages / C# / March 2008
calling base constructor
|
|
Thread rating:  |
ryanbreakspear@norubbishgmail.com - 29 Feb 2008 13:56 GMT Hi,
Is it possible to call a different base constructor (or just different parameters) in the body of a constructor in C#?
Something like:
public class test { public test(bool value) { if (value) base("True Value") else base("False Value") } }
Sorry if this doesn't make sense. In Delphi, you can do something like:
constructor Create(Value :boolean); begin if Value then inherited Create("True Value") else inherited Create("False Value); end
I've had a look around and I don't think there is a way of doing it. Can anyone confirm this either way.
Thanks
Ryan
Alex Meleta - 29 Feb 2008 14:05 GMT Hi,
Did you mean
Regards, Alex [TechBlog] http://devkids.blogspot.com
r> Hi, r> r> Is it possible to call a different base constructor (or just r> different parameters) in the body of a constructor in C#? r> r> Something like: r> r> public class test r> { r> public test(bool value) r> { r> if (value) r> base("True Value") r> else r> base("False Value") r> } r> } r> Sorry if this doesn't make sense. In Delphi, you can do something r> like: r> r> constructor Create(Value :boolean); r> begin r> if Value then r> inherited Create("True Value") r> else r> inherited Create("False Value); r> end r> I've had a look around and I don't think there is a way of doing it. r> Can anyone confirm this either way. r> r> Thanks r> r> Ryan r>
Marc Gravell - 29 Feb 2008 14:08 GMT Not in the body, but you can cheat - for example:
public test(bool value) : base(value ? "True Value" : "False Value") {} or public test(bool value) : base(Foo(value)) {}
static string Foo(bool value) { // parse the arg(s) in a more complicated way that ternary return "Bar"; }
Marc
Jon Skeet [C# MVP] - 29 Feb 2008 14:08 GMT > Is it possible to call a different base constructor (or just different > parameters) in the body of a constructor in C#? No. The base (or "this") constructor call is always the first thing that happens. However, you can still use parameters. For instance, instead of this:
> Something like: > [quoted text clipped - 8 lines] > } > } you'd have:
public test(bool value) : base (value ? "True Value" : "False Value") { }
You can call methods as well, but only static ones:
public test(bool value) : base (FormatValue(value)) { }
static string FormatValue(bool v) { if (v) { return "True Value"; } else { return "False Value"; } }
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
ryanbreakspear@norubbishgmail.com - 29 Feb 2008 14:55 GMT > ryanbreaksp...@norubbishgmail.com <ryanbreaksp...@gmail.com> wrote: > > Is it possible to call a different base constructor (or just different [quoted text clipped - 49 lines] > Jon Skeet - <sk...@pobox.com>http://www.pobox.com/~skeet Blog:http://www.msmvps.com/jon.skeet > World class .NET training in the UK:http://iterativetraining.co.uk Thanks Guys,
The ?...: syntax isn't something I've used before (and looks a bit strange to my eyes).
I've just tried it though and it does exactly what I need.
Thanks again
Ryan
Mythran - 29 Feb 2008 21:31 GMT > Thanks Guys, > [quoted text clipped - 6 lines] > > Ryan The ?...: is simply a short-circuited inline-if:
if (boolean-expression) { ... true reaches here ... } else { ... false reaches here ... }
for very simple if then else statements:
(boolean-expression) ? ... true reaches here ... : ... false reaches here ...
example:
string a = "A"; string b = "B"; string equality = (a == b ? "True" : "False");
but my example isn't the greatest...this can further be reduced to:
string a = "A"; string b = "B"; string equality = (a == b).ToString();
:P HTH, Mythran
Alex Meleta - 29 Feb 2008 14:18 GMT Hi,
It's like public test(bool value) : base ([value]) { ... } (with some restrictions, see more there http://msdn2.microsoft.com/en-us/library/ms173115.aspx)
Regards, Alex [TechBlog] http://devkids.blogspot.com
r> Hi, r> r> Is it possible to call a different base constructor (or just r> different parameters) in the body of a constructor in C#? r> r> Something like: r> r> public class test r> { r> public test(bool value) r> { r> if (value) r> base("True Value") r> else r> base("False Value") r> }
Peter Morris - 01 Mar 2008 09:43 GMT I once wrote to Anders H and asked why you can't call the base constructor at any point within your body. He was kind enough to reply with a detailed answer, unfortunately it wasn't an answer to the question I asked :-) He answered why C# doesn't have named constructors and not why you can't decide where to call a base constructor.
I have found this a bit of a pain when the base constructor calls another method, for example.
public class BaseClass { protected List<Member> Members; public BaseClass() { Members = new List<Member>(); InitializeDefaultValues(); }
protected virtual void InitializeMembers() { foreach(Member currentMember in Members) currentMember.Initialize(); } }
public class ChildClass : BaseClass { public ChildClass() : base() { Members.Add(new Member("Hello"); Members.Add(new Member("Goodbye"); } }
In this case Hello and Goodbye wont get initialized, I'd have to either explicitly call InitializeMembers or duplicate the initialization code.
It would be nice if this changed in my opinion, but I don't suppose it will. Anyway, I just thought I'd make you aware of it :-)
Pete
Marc Gravell - 01 Mar 2008 11:08 GMT >I have found this a bit of a pain when the base constructor > calls another method Well, calling a virtual method in a ctor is already risky enough - but there are ways of getting around it. I know it is a simplified example, but your version could easily be replaced with (for example):
BaseClass(params string[] members) { // (creates members, and inits them) } ChildClass() : base("Hello", "Goodbye") {}
of course, harder for more complex objects, but in C# 3 with object initializers it should be easy to pass full-formed objects to the base ctor.
Alternatively (in the base)
protected void InitAndAdd(params Member[] members) { // inits and adds members }
that your sub-class can call, which keeps it clear what happens when
Marc
Peter Morris - 01 Mar 2008 18:30 GMT > BaseClass(params string[] members) { > // (creates members, and inits them) > } > ChildClass() : base("Hello", "Goodbye") {} This code was for an object persistence framework I wrote for the Pocket PC. Having to list the members every time you create a new Person would be inappropriate I think :-)
Peter Duniho - 01 Mar 2008 19:11 GMT >> BaseClass(params string[] members) { >> // (creates members, and inits them) [quoted text clipped - 5 lines] > Having to list the members every time you create a new Person would be > inappropriate I think :-) I don't understand that comment. I don't see any real difference between listing them explicitly in the constructor (per your original example) and listing them explicitly in the call to the base constructor (per Marc's example).
If your actual code is different, then sure I suppose Marc's example wouldn't work. But that'd only be because your actual code is different from the sample you posted. It doesn't change the validity of Marc's suggestion given the example he had to work with. Garbage in, garbage out. :)
Pete
Peter Morris - 02 Mar 2008 10:18 GMT > I don't understand that comment. I don't see any real difference between > listing them explicitly in the constructor (per your original example) and > listing them explicitly in the call to the base constructor (per Marc's > example). Oh I see, I misunderstood. I thought you were suggesting
Person p = new Person("FirstName", "LastName", etc etc)
I still don't think that's a good approach anyway, because when you get inheritance of business classes it gets messy
public class Product : PersistentObject...... public class Software : Product..... public class Collateral : Product....
You'd need two constructors on each class. One for "normal" use, and one for creating the members which is called from the parameterless constructor.....
new Collateral(); ->Calls parameterless constructor ->Calls this(member list)
Now which constructor would it call on Product? Calling the one with parameters would bypass the one without parameters, calling the one without parameters would mean that the Product class would be unaware of the parameters from Collateral.
> Garbage in, garbage out. :) I agree, but in this case I think this is an example of garbage in :-)
My solution was to have a virtual CreateMembers method on PersistentObject which is called from the constructor and all classes should create their members from there. As I said, I worked around it, but I wanted this Delphi guy to realise the pitfalls of calling virtual methods when he has no control over when the base constructor is called.
Pete
Peter Duniho - 01 Mar 2008 18:08 GMT > I once wrote to Anders H and asked why you can't call the base > constructor [quoted text clipped - 4 lines] > decide > where to call a base constructor. I can't speak for him or others involved in the design of C#. However, to me it makes perfect sense that you can't call the base constructor except at the very beginning of the derived constructor. A classic convention in OOP is that by the time the derived class executes any code, the base class has been completely constructed. Allowing the base constructor to be called elsewhere would break this fundamental approach.
As far as your example goes:
> I have found this a bit of a pain when the base constructor calls another > method, for example. [quoted text clipped - 26 lines] > In this case Hello and Goodbye wont get initialized, I'd have to either > explicitly call InitializeMembers or duplicate the initialization code. Here, the base class clearly expects the derived class to override the initialization behavior. In that case, it seems obvious to me that the addition of new elements to the Members field belongs in an override of the InitializeMembers() method, given the existing design.
You don't have to duplicate anything. You just have to override the virtual method, put your initialization in there, and then call the base method after the initialization happens (yes, it's an explicit call to InitializeMembers(), but it's from the override, which is a perfectly normal and appropriate thing to do).
Frankly, the fact that in your example the InitializeMembers() method is virtual makes a very strong suggestion that it doesn't belong in the constructor at all, and that the class really should have a slightly different initialization model. One in which that initialization is handled separately from construction of the object. But even given the exact design above, the right way to deal with initialization is obvious and completely workable.
> It would be nice if this changed in my opinion, but I don't suppose it > will. I hope it doesn't. There are always good ways around the apparent limitation, and IMHO the limitation makes for a robust, reliable language. There's a reason that the limitation is present in many OOP languages (all of the ones I know of, in fact, including C#, Java, and C++).
Pete
Peter Morris - 01 Mar 2008 18:49 GMT I can't speak for him or others involved in the design of C#. However, to me it makes perfect sense that you can't call the base constructor except at the very beginning of the derived constructor. <<
Maybe they should have a word with the people who designed .NET then, because in MSIL you can apparently call the base constructor at any point you wish :-)
I don't recall the exact scenario, the one below was the best I could manage to illustrate the problem. In the past I managed to work around it but I don't recall the problem or the solution. But it was something like my example I *think*
Whatever the problem was I managed to solve it. It's just than coming from Delphi I was used to being able to initialise stuff before calling a base constructor and so I got used to it. My post was to make the original poster aware of this "pitfall".
public abstract class BaseClass { public BaseClass() { HelloMember.Value = "Hello"; GoodbyeMember.Value = "Goodbye"; }
public abstract StringMember HelloMember { get; } public abstract StringMember GoodbyeMember { get; } }
public class ConcreteClass : BaseClass { public ConcreteClass() : base { HelloMember = new StringMember("Hello"); GoodbyeMember = new StringMember("Goodbye"); }
public override StringMember HelloMember { get; private set; } public override StringMember GoodbyeMember { get; private set; } }
This will obviously throw an NullReferenceException. It's coming back to me now I think! In C# I would have to introduce a virtual method (which is what I did in my solution) which creates the members
public abstract class BaseClass { public BaseClass() { CreateMembers(); HelloMember.Value = "Hello"; GoodbyeMember.Value = "Goodbye"; }
protected abstract void CreateMembers(); public abstract StringMember HelloMember { get; } public abstract StringMember GoodbyeMember { get; } }
public class ConcreteClass : BaseClass { public ConcreteClass() : base { }
protected override void CreateMembers() {
HelloMember = new StringMember("Hello"); GoodbyeMember = new StringMember("Goodbye"); }
public override StringMember HelloMember { get; private set; } public override StringMember GoodbyeMember { get; private set; } }
Whereas by being able to call the base constructor when you choose you could do this.
public abstract class BaseClass { public BaseClass() { HelloMember.Value = "Hello"; GoodbyeMember.Value = "Goodbye"; }
public abstract StringMember HelloMember { get; } public abstract StringMember GoodbyeMember { get; } }
public class ConcreteClass : BaseClass { public ConcreteClass() { HelloMember = new StringMember("Hello"); GoodbyeMember = new StringMember("Goodbye"); base(); }
public override StringMember HelloMember { get; private set; } public override StringMember GoodbyeMember { get; private set; } }
which is less work.
Calling a constructor would allocate memory for the class's members and the constructor merely provides a way to initialise their values. By not being able to choose when to call the base constructor I must add an additional virtual method just to initialise the members.
Pete
Peter Duniho - 01 Mar 2008 19:25 GMT > I can't speak for him or others involved in the design of C#. However, > to [quoted text clipped - 5 lines] > because in MSIL you can apparently call the base constructor at any point > you wish :-) Using assembly, I could call the base constructor at any point I wish using C++ too. I don't see how that invalidates the idea that the _language_ (C# or C++) should prohibit doing so.
At a lower level you can always do all sorts of things that aren't really safe, or even approved. That doesn't mean it's a good thing to do.
> [...] > Calling a constructor would allocate memory for the class's members and [quoted text clipped - 3 lines] > able to choose when to call the base constructor I must add an additional > virtual method just to initialise the members. I don't see how that's a bad thing. It makes it a lot more clear in your code that you're doing something unconventional. As I mentioned, I really think that these sorts of things are better handled with a different initialization model anyway. But inasmuch as you insist on performing the initialization in the constructor, I think it's perfectly reasonable for the language designers to make a choice to require that sort of behavior to be more explicit.
I gather from your post that Delphi doesn't have this same restriction. However, I have to say that for me, that doesn't impress me as any sort of justification or argument in favor of allowing it in another language. I've seen other examples of people coming from Delphi and being confused or frustrated by C#'s relative rigidity. One guy who used to ask for help here had no real understanding of recursion, because he was used to iterating through a recursive data structure in Delphi, which apparently hid the recursion from him (it exposed the collection as a linear list).
If anything, these things just reinforce my feeling that, assuming what people say about Delphi is true, that Delphi is not a very good OOP language.
By the way, I take back what I wrote about all OOP languages I know having this restriction. You've already mentioned Delphi and while I didn't know it didn't have this restriction, I already knew of another language that also doesn't. Objective-C is similarly "flexible" in its rule about construction. But again, I find this to be a bad thing...along with the fact that in Objective-C it's possible to have an object that has _never_ been fully initialized (derived classes inherit base class constructors, which can lead to allocation of an instance of a class without ever calling the constructor for that class or any class in the hierarchy between the actual class and the constructor you actually called...ugh!), this kind of flexibility just leads to weird, hard-to-figure-out bugs.
Pete
Peter Morris - 02 Mar 2008 10:11 GMT > Using assembly, I could call the base constructor at any point I wish > using C++ too. I don't see how that invalidates the idea that the > _language_ (C# or C++) should prohibit doing so. MSIL isn't assembly. My point was that it is valid in .NET, and .NET protects you from a lot of "dodgy" practises.
> I don't see how that's a bad thing. It makes it a lot more clear in your > code that you're doing something unconventional. As I mentioned, I really > think that these sorts of things are better handled with a different > initialization model anyway. But inasmuch as you insist on performing the > initialization in the constructor, No, that's inaccurate. It is fair to say "I originally put my creation in the constructor". I thought it was pretty clear that I changed it to create the members in CreateMembers(), hence the name.
> I gather from your post that Delphi doesn't have this same restriction. No.
> However, I have to say that for me, that doesn't impress me as any sort of > justification or argument in favor of allowing it in another language. I didn't argue that it should be allowed because it is in Delphi. I argued that it is perfectly valid in .NET, and that I was used to it because I came from Delphi.
> I've seen other examples of people coming from Delphi and being confused > or frustrated by C#'s relative rigidity. One guy who used to ask for help > here had no real understanding of recursion, Then I would argue he was a beginner, or crap.
>because he was used to iterating through a recursive data structure in >Delphi, which apparently hid the recursion from him (it exposed the >collection as a linear list). This is no different to .NET presenting a tree structure in a linear way using an IEnumerable. The fact is that Delphi doesn't "hide" recursion from the programmer, many Delphi programs use recursion, for example to find all files in a directory structure. Your assumption is incorrect and based on a single case.
> If anything, these things just reinforce my feeling that, assuming what > people say about Delphi is true, that Delphi is not a very good OOP > language. Again I would argue that you are incorrect. Delphi is very similar to C# which is why I found C# so easy to pick up. In my experience many Delphi programmers think in a procedural way and merely write methods in events, but I have not experience much difference in C# either to be honest. My point is, you can't judge a language by its users.
> By the way, I take back what I wrote about all OOP languages I know having > this restriction. You've already mentioned Delphi and while I didn't know > it didn't have this restriction, I already knew of another language that > also doesn't. Objective-C is similarly "flexible" in its rule about > construction There is also Chrome from www.RemObjects.com, I believe this allows you to call the constructor at any point you wish.
> But again, I find this to be a bad thing If everyone in the world shared the same opinions it would be a truely dull place to live :-)
> fact that in Objective-C it's possible to have an object that has _never_ > been fully initialized (derived classes inherit base class constructors, > which can lead to allocation of an instance of a class without ever > calling the constructor for that class or any class in the hierarchy > between the actual class and the constructor you actually called...ugh!), > this kind of flexibility just leads to weird, hard-to-figure-out bugs. It's perfectlly possible in C# to introduce bugs that do not initialise all of your members properly, for example
public class MyClass { protected int? SomeValue; protected string Name;
public MyClass(int value) { SomeValue = value; }
public MyClass(int value, string name) // : this(value) { Name = name; } }
In this example the developer has forgotten the call to this(value). This is an equivalent scenario to not calling a base constructor, you end up with a partially initialised object. Every language allows the developer to write bugs in one way or another, it's up to the developer to have good practises to try to avoid them as much as possible and ensure they are not released.
Here is another example of a bug:
class Program { static void RecordChangedValue(object newValue) { object oldValue = 1; if (newValue != oldValue) throw new ArgumentNullException("Value seems to have changed"); }
static void Main(string[] args) { RecordChangedValue(1); } }
I encountered something like this when implementing in-memory transaction/rollback on my OPF. When a member is modified within a transaction its original value is stored as a System.Object, so everything is compared as System.Object, but in this case 1 does not equal 1 because the default implementation for object comparision is ByRef and not ByValue.
That's a behaviour specific to .NET. I am aware of it so I avoid it when I write code.
Pete
Peter Duniho - 02 Mar 2008 10:47 GMT > [...] > It's perfectlly possible in C# to introduce bugs that do not initialise > all > of your members properly, I'm not talking about lack of "proper" initialization. I'm talking about lack of initialization period.
In the C# example you posted, _a_ constructor gets called for every class in the inheritance hierarchy. You may have a bug in which the wrong one is called, but there's always one that gets called. In Objective-C, it is possible for a constructor for one or more classes in the hierarchy to simply not be called at all.
Anyway, it sounds like Delphi was unfairly represented by the other person. I still stand by my opinion that it's a good thing to require base constructors to have all finished executing before any derived constructor gets to execute.
Pete
Peter Morris - 02 Mar 2008 11:48 GMT > I'm not talking about lack of "proper" initialization. I'm talking about > lack of initialization period. Delphi doesn't do that. The first constructor that is executed will create all of the required memory etc for the whole hierarchy, the constructor code is initialisation only.
> I still stand by my opinion that it's a good thing to require base > constructors to have all finished executing before any derived > constructor gets to execute. And although I have a work around and do not struggle with the current implementation I expect I will stand by my opinion too :-)
Pete
Thana at Thailand - 02 Mar 2008 10:53 GMT I faced this problem in my work.
I designed custom Exception that has custom fields ex: - severity ex. "E" - error, "W" - warning - ErrCode ex. "001","002",...
then I want to create a constructor that get input from string ex: "E,001,Error Message" ( the real format is slightly different and it is the standard error code and message of my mainframe host apps)
then my Exception will contain fields :
- severity = "E" - errCode = "001" - Message = "Error Message" ( this field need to pass to System.Exception constructor )
class MyException : Exception { // fullMsg ex. "E,001,Error Message" MyException(string fullMsg) : base( cutMsg(fullMsg) ) { severity = ... (ex. "E") errCode = ... (ex. "001") }
private static string cutMsg(string fullMsg) { return ... (ex. "ErrorMessage") } }
This is quite not straightforward. because in cutMsg() method, I can split string and get all fields ( E , 001, Error Message ) but I can return only "Error Message" to init at base constructor
and then I need to re-split message again to get "E" and "001" at body of constructor.
I think that currently C# don't have neat syntax to solve this problem. To solve this neatly, it is needed to introduce 'calling base constructor in the body of child constructor' syntax. As in VB.Net and Java can.
I love C# but find this flaw quite borther me. So, do I need to accept doing it in indirect way?
ps. This way, if constructor has 3 arguments, then you need to create 3 static method (ex. cutMsg() ) for parse each argument.
- : Exception(cutMsg1(), cutMsg2(), cutMsg3())
quite redundant
Very appriciate, if anyone have any suggestions. Thanks.
Peter Duniho - 02 Mar 2008 11:27 GMT > [...] > then my Exception will contain fields : [quoted text clipped - 3 lines] > - Message = "Error Message" ( this field need to pass to > System.Exception constructor ) If your exception class has three fields, why doesn't the constructor have three parameters, one for each field?
For example:
class MyException : Exception { public MyException(string severity, string errCode, string message) : base(message) { this.severity = severity; this.errCode = errCode; } }
I also don't see what's so terrible about this example you posted:
> class MyException : Exception > { [quoted text clipped - 10 lines] > } > } I wouldn't use it unless for some reason there was some really compelling reason that forced you to have the constructor take just a single string as a parameter _and_ you also for some reason were forced _not_ to be able to have a separate method create the instance for you, as in:
class MyException : Exception { public MyException(string severity, string errCode, string message) : base(message) { this.severity = severity; this.errCode = errCode; }
public static MyException FromFullMessage(string fullMsg) { // split string here, then... return new MyException(severity, errCode, message); } }
But any of these alternatives seem reasonable to me, even if I like your version the least.
> This is quite not straightforward. > because in cutMsg() method, I can split string and get all fields ( E , [quoted text clipped - 3 lines] > and then I need to re-split message again to get "E" and "001" at body > of constructor. Sounds like a great argument for passing each part of the string individually in the first place, or for using a static "From..." method.
> I think that currently C# don't have neat syntax to solve this problem. > To solve this neatly, it is needed to introduce 'calling base > constructor in the body of child constructor' syntax. As in VB.Net and > Java can. I can't speak for VB.NET. Though, given the other things VB.NET does that I don't like, it wouldn't surprise me. But in Java, while you do call "super()" from inside the constructor, you don't get to execute any code before it. It has to be the first thing. It's not really any different from C# or C++ in practice.
> I love C# but find this flaw quite borther me. > So, do I need to accept doing it in indirect way? I disagree that it's a flaw. But yes, whether you think it's a flaw or not, that's how the language is. You must "accept doing it in indirect way".
I've yet to see an example of where this particular design choice forces some completely inappropriate alternative on a person. Yes, the code sometimes needs to be different. But it never has to be bad.
> ps. This way, if constructor has 3 arguments, then you need to create 3 > static method (ex. cutMsg() ) for parse each argument. > > - : Exception(cutMsg1(), cutMsg2(), cutMsg3()) > > quite redundant Honestly, when you start getting into something like that, I personally think that the language is giving you a nice big hint that there's something awkward about your design. A constructor that takes three strings, each of which needs to be parsed so that some portion of the string can then be passed to the base class, that's just asking to be redesigned into something simpler and easier to use.
But in any case, you can always have a separate method to handle the preprocessing _and_ instantiation, if you find that you don't like hammering the constructor base-calling syntax into your existing design.
Pete
Thana at Thailand - 02 Mar 2008 12:53 GMT Thanks Peter Duniho,
Your solution is impressed me. I never thought about it before.
So, your solution is to use child class constructor argument in the same format as the base class constructor argument to avoid complex processing of argument.
Then use a static method (as factory) that parse the complex argument to simple arguments and use that to create child class instead.
quote < Peter Duniho >
> class MyException : Exception > { [quoted text clipped - 11 lines] > } > } This solution relieves me very much.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|