Formular una preguntaFormular una pregunta
 

RespondidaSmall or big C# contructor

  • martes, 26 de agosto de 2008 18:44Danut Prisacaru Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     

    I have a dilemma and a dispute with some colleagues: should the constructor of a C# class do a lot or the minimum and latter in a method call put a lot of logic?

    I am coming from a C++ background and there it is better to do just simple data initialization in the constructor, throwing an exception from a constructor is bad since the object is not fully constructed yet.

    Does the same argument work in C#?

    Should I do the minimum work in the constructor?

    My colleagues' position is that having a minimal constructor will leave the state of the object as not fully defined and then changed by a subsequent call to another method.

    Is there a book or an article that gives more details?

    Thanks!



    http://danutp.blogspot.com/

Respuestas

  • martes, 26 de agosto de 2008 18:53David M MortonMVP, ModeradorMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     Respondida
    It depends on what you need to get done.  If you're going to call this method every time after you instantiate your object, I'd just put the method logic in the constructor, so you only have to make one method call (the constructor itself).  If this object depends on certain properties being set, then I would most certainly set them in the constructor.  Either way, you're going to set the properties somewhere, so I see it as six one way, half-a-dozen the other.
    David Morton - http://blog.davemorton.net/
  • martes, 26 de agosto de 2008 18:58Robert C. Barth Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     RespondidaTiene código
    As much as is necessary should be done so that the object can be used by its clients. Throwing an exception in the constructor is fine if you treat the object as invalid (as should be done anytime an exception is thrown on instantiation of an object).

    If your use-case for the object is:

    SomeObject obj = new SomeObject();  
    obj.Initialize(); // Or something very similar, every time 

    then it's kind of silly to even have the initialize method that gets called by the client every time. Besides the fact that it subtly breaks the rules of encapsulation (you're exposing some of how your object operates to the outside world).
  • miércoles, 27 de agosto de 2008 7:52nobugzMVP, ModeradorMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     Respondida
    The rule in C# is not quite as strict as in C++.  If the class has a Dispose() method or a finalizer, it should not throw an exception in the constructor.  That's a hard rule for a finalizer, you'll leak if you throw.  But a weak rule for Dispose(), the garbage collector will eventually finalize the object's you'd normally dispose.  If Dispose() isn't critical or you have neither, it is just fine to do anything you want, the garbage collector will catch the debris of an accident.  You'll never leak memory like you do in C++.
    Hans Passant.
  • miércoles, 27 de agosto de 2008 22:47Greg Beech Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     Respondida
    I decided this one was worth writing up as a blog entry, because it's a generally interesting topic and something I'll probably want to refer back to in the future. It includes a simple program to demonstrate the reasoning behind my answer.

    http://gregbeech.com/blogs/tech/archive/2008/08/27/disposing-and-finalizing-partially-constructed-objects.aspx

    If you don't want to go off-site to read it then the gist is "In summary, do as much work as needed to get the object in a usable state in the constructor, but clean up any expensive managed resources you allocate in an exception handler if you can't complete it successfully."

    http://gregbeech.com/blogs/tech

Todas las respuestas

  • martes, 26 de agosto de 2008 18:53David M MortonMVP, ModeradorMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     Respondida
    It depends on what you need to get done.  If you're going to call this method every time after you instantiate your object, I'd just put the method logic in the constructor, so you only have to make one method call (the constructor itself).  If this object depends on certain properties being set, then I would most certainly set them in the constructor.  Either way, you're going to set the properties somewhere, so I see it as six one way, half-a-dozen the other.
    David Morton - http://blog.davemorton.net/
  • martes, 26 de agosto de 2008 18:58Robert C. Barth Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     RespondidaTiene código
    As much as is necessary should be done so that the object can be used by its clients. Throwing an exception in the constructor is fine if you treat the object as invalid (as should be done anytime an exception is thrown on instantiation of an object).

    If your use-case for the object is:

    SomeObject obj = new SomeObject();  
    obj.Initialize(); // Or something very similar, every time 

    then it's kind of silly to even have the initialize method that gets called by the client every time. Besides the fact that it subtly breaks the rules of encapsulation (you're exposing some of how your object operates to the outside world).
  • martes, 26 de agosto de 2008 20:27boban.sMVPMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     
     It's very normal to have a constructor that accepts all the values for properties. I found this very useful, especially when you want to change (remove or add) some property, and you use this constructor in many places of your solution. So if you change the constructor, you will have to change every line where this constructor is used, to be able to start application.
    When I use CodeSmith for some old projects to generate all the entities from database, I intentionally create only one constructor with all values in it.
    But this is my view. Probably others will have completely oposite opinion. But if you found this way useful in your scenario, go for.
    MCDBA, MCSD, MCITP http://sharpsource.blogspot.com/
  • miércoles, 27 de agosto de 2008 7:52nobugzMVP, ModeradorMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     Respondida
    The rule in C# is not quite as strict as in C++.  If the class has a Dispose() method or a finalizer, it should not throw an exception in the constructor.  That's a hard rule for a finalizer, you'll leak if you throw.  But a weak rule for Dispose(), the garbage collector will eventually finalize the object's you'd normally dispose.  If Dispose() isn't critical or you have neither, it is just fine to do anything you want, the garbage collector will catch the debris of an accident.  You'll never leak memory like you do in C++.
    Hans Passant.
  • miércoles, 27 de agosto de 2008 14:42barnarddale Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     Tiene código
     If you need to throw an exception in a constructor, I think the only rule of thumb would be to clean up anything you've done before hitting the problem:

    myconstructor {
    try {
        do something 1
        do something 2
        do something 3 oops an exception got thrown after a couple of things were already done--we'd better clean them up
        do something 4
    }
    catch all {
        Dispose();
        re-throw;
    }
    }

    In your Dispose method, you should check each appropriate field like this. It makes it easy to dispose partially constructed objects as well as fully constructed objects:
    if (myField != null) {
        myField.Dispose();
        myField = null;
    }
    if (myList != null) {
        while (myList.Count > 0) {
            myList[0].Dispose();
            myList.RemoveAt(0);
        }
        myList.Dispose();
        myList = null;
    }

    • Editadobarnarddale miércoles, 27 de agosto de 2008 14:43clarification
    •  
  • miércoles, 27 de agosto de 2008 14:49Stephen C Martin Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     
    I'd have to disagree with your rules for C#. I tend to feel that the only rule related to throwing exceptions from constructors is that any Disposable or unmanaged resources allocated must be cleaned up prior to throwing the exception (and SuppressFinalize called if appropriate). This renders the Dispose() method and any finalizer moot.
  • miércoles, 27 de agosto de 2008 22:47Greg Beech Medallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuarioMedallas del usuario
     Respondida
    I decided this one was worth writing up as a blog entry, because it's a generally interesting topic and something I'll probably want to refer back to in the future. It includes a simple program to demonstrate the reasoning behind my answer.

    http://gregbeech.com/blogs/tech/archive/2008/08/27/disposing-and-finalizing-partially-constructed-objects.aspx

    If you don't want to go off-site to read it then the gist is "In summary, do as much work as needed to get the object in a usable state in the constructor, but clean up any expensive managed resources you allocate in an exception handler if you can't complete it successfully."

    http://gregbeech.com/blogs/tech