MSDN > フォーラム ホーム > Visual C# General > Small or big C# contructor
質問する質問する
 

回答済みSmall or big C# contructor

  • 2008年8月26日 18:44Danut Prisacaru ユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダル
     

    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/

回答

  • 2008年8月26日 18:53David M MortonMVP, モデレータユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダル
     回答済み
    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/
  • 2008年8月26日 18:58Robert C. Barth ユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダル
     回答済みコードあり
    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).
  • 2008年8月27日 7:52nobugzMVP, モデレータユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダル
     回答済み
    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.
  • 2008年8月27日 22:47Greg Beech ユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダル
     回答済み
    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

すべての返信

  • 2008年8月26日 18:53David M MortonMVP, モデレータユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダル
     回答済み
    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/
  • 2008年8月26日 18:58Robert C. Barth ユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダル
     回答済みコードあり
    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).
  • 2008年8月26日 20:27boban.sMVPユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダル
     
     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/
  • 2008年8月27日 7:52nobugzMVP, モデレータユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダル
     回答済み
    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.
  • 2008年8月27日 14:42barnarddale ユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダル
     コードあり
     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;
    }

    • 編集済みbarnarddale 2008年8月27日 14:43clarification
    •  
  • 2008年8月27日 14:49Stephen C Martin ユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダル
     
    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.
  • 2008年8月27日 22:47Greg Beech ユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダルユーザーのメダル
     回答済み
    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