1

我有各种派生对象,我希望用户能够使用对象初始值设定项。我有一个“初始化”属性,我希望在设置这些字段时为真,然后我希望随后将 Initializing 属性设置为 false。

我如何判断对象初始化器何时完成才能执行此操作?

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

在上面的示例中,如果您使用构造函数,它可以正常工作。但是,如何使其与对象初始化程序以相同的方式工作是问题所在。

编辑:对于所有反对者,这里有其他人正在寻找我所追求的 - http://blogs.clariusconsulting.net/kzu/how-to-make-object-initializers-more-useful/

不幸的是,它看起来确实是不可能的。

4

6 回答 6

4

如果您确实需要跟踪对象的初始化,那么您需要手动实现该逻辑。一种方法是复制 WinForms 代码生成器使用的内容。当对象希望批量更新属性时,它们会公开ISupportInitialize接口。所以用法会像......

var x = new Foo();
x.BeginInit();
x.Property1 = 1;
x.Property2 = 2;
x.EndInit();
于 2012-02-09T04:54:39.667 回答
3

设置任何标志都没有意义。在初始化程序运行之前,您无法访问对象。例如:

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

由于在设置 Prop1 之前无法访问从 new 返回的引用,因此无法访问任何属性,因此无需控制访问或担心它是否“完成”。

虽然,我想我可以看到你可能会有这样的事情:

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

如果这是您所关心的,那么您的对象设计不正确。属性不应该有那样的副作用。无法知道是否所有初始化都已完成。

于 2012-02-09T04:41:59.417 回答
1

由于对象初始化只是语法糖,因此您无法区分它与普通属性集之间的区别。我也想不出一个合理的案例,你想以不同的方式对待他们。

也就是说,如果您说必须设置至少 1 个 x 属性(无论是速记还是速记语法),那么您可以在 ctor 中将 initializing 设置为 true,然后在每个属性集上将其设置为 false。

于 2012-02-09T04:39:40.437 回答
1

这个问题没有意义。对象初始化器语法只是语法糖的简写。

这个:

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

与此完全相同:

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

没有“完成”可检测。

你想做的事情我们可以做到:

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

或者,让 ctor 采用值的初始状态,然后保证设置。

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

编辑

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
    }
}
于 2012-02-09T04:37:58.893 回答
1

与其依赖显式属性来告诉您何时初始化对象,不如让您的DoSomething方法验证它是否具有完成其工作所需的信息。您的示例非常粗糙,我希望您的实际实现更复杂,所以我只是假设Property1并且Property2必须分配给某些东西(意味着在继续之前不是空字符串):

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

更新

在不了解您实际使用的对象模型的情况下,这里有一个基于在整个框架中广泛使用的模型的可能替代方案:

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

或者

class Foo
{
    private FooConfig config_;

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

    public void DoSomething()
    {
    }
}

在哪里FooConfig定义:

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

DoSomething使用以下方式调用:

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

或者

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

Foo这可以很容易地更改以适应在或上的构造函数使用FooConfig

于 2012-02-09T05:17:38.343 回答
0

对象初始化器只是创建对象并在其上设置一堆属性的简写。问“什么时候完成”是没有意义的。

如果您希望对象的状态取决于正在初始化的特定属性集,那么您可以将代码添加到每个属性的设置器并在内部跟踪它。但是,这实际上取决于您要实现的目标。

更新

只是阅读您对@asawyer 答案的评论。无法判断是否在初始化程序中设置了属性。只是为了说明 - 这里有三段代码做完全相同的事情,除了你似乎想要每个不同的行为。

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";

跟踪单个属性设置器的执行并不难,并且除了第一次执行之外都会触发一些副作用,但是说我只想在客户端更改初始对象配置时触发副作用是没有意义的在ctor完成后。

于 2012-02-09T04:38:42.447 回答