2

I have various derived objects that I would like the user to be able to use object initializers with. I have an "Initializing" property that I want to be true as those fields are being set and then I want the Initializing property to be set to false afterward.

How can I tell when the object initializer is done to be able to do this?

class Foo
{    
    Public Foo(string p1, string p2)
    {
        Initializing = true;
        Property1 = p1;
        Property2 = p2;
        Initializing = false;
    }

    bool Initializing;

    string _property1;
    string Property1 
    {
        get { return _property1; } 
        set { _property1 = value; DoSomething(); }
    }

    string Property2 { get; set; }

    public void DoSomething()
    {
        if(Initializing) return; // Don't want to continue if initializing
        // Do something here
    }
}

In the above example, it works fine if you use the constructor. How to make it work the same way with an object initializer is the problem though.

EDIT: For all you naysayers, here's someone else looking for exactly what I'm after - http://blogs.clariusconsulting.net/kzu/how-to-make-object-initializers-more-useful/

Unfortunately it does look likes it's an impossibility though.

Brandon Moore
  • 8,590
  • 15
  • 65
  • 120
  • Can you post some code to illustrate better what you want to do? – Andrew Cooper Feb 09 '12 at 04:36
  • 1
    @BrandonMoore That is a really bad idea. You literally made me shudder. – asawyer Feb 09 '12 at 04:45
  • @BrandonMoore - And that'll earn you a downvote (and a comment flag). – M.Babcock Feb 09 '12 at 04:51
  • 2
    @BrandonMoore Mainly because I have no idea how you managed to get into this situation, and how bad your actual project is affected. So I'm hesitant to offer advice that might require a huge amount of retooling a project I know nothing about. – asawyer Feb 09 '12 at 04:53
  • @M.Babcock Sorry if I get offended when people say "Hey, you're a freaking idiot" in any variation. How about we all just vote to close this question cause apparently no one here is interested in being helpful right now. – Brandon Moore Feb 09 '12 at 04:54
  • There, I made the first close vote so just need 4 more of you to help out. – Brandon Moore Feb 09 '12 at 04:55
  • @M.Babcock hey, can you flag that last post I made too, I think it might be offensive also. – Brandon Moore Feb 09 '12 at 04:57
  • @BrandonMoore See my edit for a way to fix your example code fairly easily. – asawyer Feb 09 '12 at 04:58
  • 1
    @BrandonMoore I'm sorry you don't like the answers your getting Bradon. The problem is you've really backed your self into a corner here. The main problem is your doing things with property setters that should not be depening on the order the properties are set. Your ctor code though, thats fine, you can set the backing stores, and call out the side effects in any manner you chose to do so. I'm just concerned that because of a misunderstanding you might have much better problems. Lashing out isnt going to help, folks around here are generally very helpful and friendly, and go out of their way – asawyer Feb 09 '12 at 05:02
  • @BrandonMoore - I've been following your question for a while and I actually have an answer stored in cache that might help but if you're going to ask for help then you should show some respect to the people who have already taken time to try to help you. Rule #1 on SO is be nice. I deal with this crap with my kids every day and hope to god not to have to read it on here too... – M.Babcock Feb 09 '12 at 05:03
  • @BrandonMoore to help other people on a subject that we all love. I am very sorry your having trouble, I suggest maybe asking a new question that is more focused on your specific problem rather then the more general answer you where hoping to get here. – asawyer Feb 09 '12 at 05:03
  • @M.Babcock May as well post your solution, I would like to see it at least. – asawyer Feb 09 '12 at 05:04
  • @asawyer I'm sorry I mistook your "You literally just made me shudder" comment for being anything less than friendly. – Brandon Moore Feb 09 '12 at 05:13
  • @BrandonMoore It's ok. I just happen to know the pain of a class with crazy side effect producing properties and the havoc it can cause. – asawyer Feb 09 '12 at 05:14
  • @BrandonMoore - If you can provide a minor edit to your question, I'll be able to retract the downvote. BTW - I posted my answer, I'm not sure that it'll work in your situation and I know it isn't pretty (I'm good at that) but to me it makes sense. – M.Babcock Feb 09 '12 at 05:25
  • @asawyer - There, it's posted... please limit the criticisms to constructive ones. ;) – M.Babcock Feb 09 '12 at 05:26
  • @asawyer That was sarcasm. The point was that what you said wasn't friendly and you should not be surprised if people respond adversely when you say things like that. – Brandon Moore Feb 09 '12 at 05:31

6 Answers6

4

If you really need to track initialization of your object then you need to implement that logic manually. One approach is to copy that used by the WinForms code generator. Where objects expose the ISupportInitialize interface when they want properties to be updated in a batch. So usage would be something like...

var x = new Foo();
x.BeginInit();
x.Property1 = 1;
x.Property2 = 2;
x.EndInit();
Phil Wright
  • 22,580
  • 14
  • 83
  • 137
  • +1 For being the only constructive person here and posting something useful even though it doesn't quite help my situation. I think I just need to find a better approach, because what I'm wanting is basically to treat the object initializer like a constructor of sorts even though I know that's not what it is. – Brandon Moore Feb 09 '12 at 05:19
  • @BrandonMoore: I was going to answer this as well. ***This is how you do it.*** You should check and throw if BeginInit/EndInit haven't been called or have not been called in the correct order. The only other alternative is to provide a ctor that takes a type which contains all data needed to initialize your type. That's another pattern found in the framework (check out the AppDomain as a related example). This is the answer, so you don't need to ask anything again, other than a new question. –  Feb 10 '12 at 16:51
  • @Will Thanks. Obviously not what I was hoping to hear but it is what it is :/ – Brandon Moore Feb 11 '12 at 01:05
3

There is no point in setting any flag. You cannot access an object until after the initializers have run. For example:

var object = new object() { Prop1 = "Boo" }

Since the reference returned from new cannot be accessed until after Prop1 is set, there is no way to access any of the properties, thus no need control access or worry about whether it is or isn't "done".

Although, I suppose I can see how you might have something like this:

public class Foo {
    private int _value;
    public int Bar {
        set {
            _value = value * Baz; // don't want to do this if initializing
        }
    }

    public int Baz { get; set; }
}

If this is what you're concerned about, then you are designing your objects incorrectly. Properties should not side effects like that. There is no way to know if all the intializing has been done.

Erik Funkenbusch
  • 92,674
  • 28
  • 195
  • 291
1

This question makes no sense. The object initializer syntax is just syntactic sugar shorthand.

This:

var myInstance = new someClass()
{
    Prop1 = "",
    Prop2 = "",
    Prop3 = "",
    Prop4 = "",
    Prop5 = ""
}

Is exactly the same as this:

var myInstance = new someClass();
myInstance.Prop1 = "";
myInstance.Prop2 = "";
myInstance.Prop3 = "";
myInstance.Prop4 = "";
myInstance.Prop5 = "";

There is no "Done" to be detected.

What you want to could be done we something like:

class someClass()
{
  public string AStringProperty { get; set; }
  public bool IsInitiazlied 
  {
    return string.IsNullOrWhitespace(this.AStringProperty);
  }
}

Or, make the ctor take the inital state of the values, then your guarantied to be setup.

class someClass()
{
  public string AStringProperty { get; set; }
  public someClass(string AStringPropertyInit)
  {
      this.AStringProperty = AStringPropertyInit;
  }
}

EDIT

class Foo
{    
    Public Foo(string p1, string p2)
    {

        _property1= p1; //set the backing store directly, 
                        //skips the side effect in the setter
        Property2 = p2;

        DoSomething(); // now cause the side effect
                       // we know everything is setup
    }



    string _property1;
    string Property1 
    {
        get { return _property1; } 
        set { _property1 = value; DoSomething(); }
    }

    string Property2 { get; set; }

    public void DoSomething()
    {
        // Do something here
    }
}
asawyer
  • 17,642
  • 8
  • 59
  • 87
  • The term is "syntactic sugar" ;) – Jeff Mercado Feb 09 '12 at 04:40
  • @asawyer Thanks for finally trying to help. I don't want the stuff in DoSomething() to run if the properties are being set from an initializer, but I do if they're not called from an initializer. The idea is that when I'm initializing the object, it's in its "initial" state. But when properties change then I actually want DoSomething() to run. So this solution doesn't quite solve that problem yet. – Brandon Moore Feb 09 '12 at 05:06
  • @BrandonMoore When you say initializer do you mean constructor ? – asawyer Feb 09 '12 at 05:09
  • (sigh) No. I just put the constructor there as an example of the behavior I'm looking for. But because of other constraints (like the class's use in a generic type) I don't want to have any constructor other than the default public one. – Brandon Moore Feb 09 '12 at 05:16
  • @BrandonMoore See Phil Wright's answer. You'll need to do something like that, and I can almost guarantee is going to be more of a headache then its worth. – asawyer Feb 09 '12 at 05:17
1

Since object initialization is just syntactic sugar, you can't tell the difference between it and normal property sets. Nor can I think of a reasonable case where you'd want to treat them differently.

That said, if you're saying that at least 1 of x properties must be set (whether longhand or shorthand syntax), then you can set initializing to true in the ctor, and then set it false on every property set.

Mark Brackett
  • 84,552
  • 17
  • 108
  • 152
1

Rather than depending on an explicit property to tell you when your object is initialized, you could have your DoSomething method validate that it has the information it needs to do its job. Your example is pretty crude and I expect your real implementation is more complex so I'll just assume that Property1 and Property2 have to be assigned to something (meaning just not an empty string before continuing):

class Foo
{    
    public Foo(string p1, string p2)
    {
        Property1 = p1;
        Property2 = p2;
    }

    string Property1 { get; set; } 
    string Property2 { get; set; }

    public void DoSomething()
    {
        // *** Replace this with something valid to your real code
        if(!string.IsNullOrEmpty(Property1) || !string.IsNullOrEmpty(Property2)) 
            return; // Don't want to continue if not initialized
        // Do something here
    }
}

UPDATE

Having no knowledge of the object model you're actually working with, here's a possible alternative based on a model used widely throughout the framework:

class Foo
{
    public void DoSomething(FooConfig config)
    {
    }
}

OR

class Foo
{
    private FooConfig config_;

    public Foo(FooConfig config)
    {
        config_ = config;
    }

    public void DoSomething()
    {
    }
}

Where FooConfig is defined:

class FooConfig
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
}

And DoSomething is invoked using:

(new Foo()).DoSomething(new FooConfig() { Property1 = "abc"; Property2 = "def"; });

OR

(new Foo(new FooConfig() { Property1 = "abc"; Property2 = "def"; })).DoSomething();

This could easily be changed to accommodate constructor usage on either Foo or FooConfig.

M.Babcock
  • 18,753
  • 6
  • 54
  • 84
  • The thing is just that I want DoSomething to run if a property has been "Changed". But if the object was initialized with the property I don't want DoSomething to run. – Brandon Moore Feb 09 '12 at 05:28
  • @BrandonMoore - That is a bit confusing. So you want `DoSomething` to run if the property has a value, as long as it wasn't set explicitly through the property's `set` method? – M.Babcock Feb 09 '12 at 05:32
  • Well... obviously if it's set from the initializer then it 'is' set through the set method, although I understand what you're trying to say. Except that the issue isn't whether it's set "explicitly" through the setter but whether it was set through the initializer. In my current approach those two things might seem synonymous, but the difference is that maybe there's a better approach to what I'm actually trying to do whereas there may not be to the other. I don't 'have' to do it the way I'm proposing, if there's a better design I'm all for trying it. – Brandon Moore Feb 09 '12 at 05:36
  • @BrandonMoore - That is almost the point to my answer though. `DoSomething` doesn't care if the object is initialized (arguably it shouldn't) it is only interested in if it has the information it needs to perform its task. I'll update my answer with an alternative that might improve the situation a little. – M.Babcock Feb 09 '12 at 05:45
  • So if DoSomething's purposes includes saving the last state of the property are you going to argue I shouldn't do that? ;) – Brandon Moore Feb 09 '12 at 05:51
  • @BrandonMoore - I'm not arguing. I'm trying to help you find a solution. :) With the limited information provided it would be hard to provide a solid answer. We don't know what your implementation of `Foo` actually does or the impact of `Property1` and `Property2` on your application. The best we can do is provide alternatives based on experience and hope that they fit your solution. – M.Babcock Feb 09 '12 at 05:59
  • Sorry, let me rephrase that: the purpose of DoSomething() 'is' to mark that object dirty. Except DoSomething is in an aspect that is applied to the class and multicasted to the properties. – Brandon Moore Feb 09 '12 at 06:10
  • @BrandonMoore - This feels an awful lot like scope creep since none of this information was disclosed in your original question. Now your question seems to sound more like 'How can I know when a property on an object changes?' This is the purpose for interfaces like `INotifyPropertyChange`. It contains an event that will be raised when an object changes. – M.Babcock Feb 09 '12 at 06:20
  • Huh? I have no problem knowing when the property changes. I have a problem knowing if it's done so in an initializer (or more accurately: knowing when the initializer is done) exactly like my question says. And from what I can surmise from these answers and other stuff I've found on the google it looks like it's not possible at this point in time. A few minutes ago I finally found where a guy from Microsoft liked the idea of being able to do so but said it couldn't be fit into the current upcoming version (4 at the time) but would add it to a list for consideration for the next version. – Brandon Moore Feb 09 '12 at 06:50
0

An object intializer is just a short-hand for creating an object and setting a bunch of properties on it. It doesn't relaly make sense to ask "when is it complete".

If you want the state of your object to depend on a particular set of properties being initialised then you could add code to the setter for each property and track it internally. It really depends, though, what you're trying to achieve.

Update

Just reading your comments on @asawyer's answer. There's no way to tell if a property is being set in the initialiser or not. Just to illustrate - here are three pieces of code that do exactly the same thing, except that you seem to want a defferent behaviour for each.

var someVar1 = new SomeClass()
               {
                    Prop1 = "value1";
                    Prop2 = "value2";
               };

var someVar2 = new SomeClass()
               {
                    Prop1 = "value1";
               };
someVar2.Prop2 = "value2";

var someVar3 = new SomeClass();
someVar3.Prop1 = "value1";
someVar3.Prop2 = "value2";

It wouldn't be hard to track the execution of individual property setters, and trigger some side-effect on all but the first execution, but to say I only want to trigger the side effect if the client changes the initial object configuration makes no sense after the ctor has finished.

Andrew Cooper
  • 32,176
  • 5
  • 81
  • 116
  • Don't equate a limitation with logic. Just because something can't be done doesn't mean it wouldn't make sense to do it if you could. – Brandon Moore Feb 09 '12 at 05:40
  • @BrandonMoore The point, though, is that in C#, and probably in most OO languages, the initial state of an object is what you have after the constructor is complete. As has been said before, an object initialiser is just syntactic sugar for setting a bunch of properties. The same thing can be done with a default constructor and explicit property calls. If you want to force a user of your class to set a specific set of properties before the object is considered initilaised then your better off coding that in a constructor and not having a default constructor. – Andrew Cooper Feb 09 '12 at 06:05