Domanda

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.

È stato utile?

Soluzione

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();

Altri suggerimenti

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.

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.

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
    }
}

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.

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top