如何判断对象初始值设定项何时完成

本文关键字:何时完 何判断 判断 对象 | 更新日期: 2023-09-27 18:23:47

我有各种派生对象,我希望用户能够使用对象初始值设定项。 我有一个"正在初始化"属性,我希望在设置这些字段时为 true,然后我希望初始化属性之后设置为 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/

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

如何判断对象初始值设定项何时完成

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

var x = new Foo();
x.BeginInit();
x.Property1 = 1;
x.Property2 = 2;
x.EndInit();

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

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

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

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

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

这个问题

毫无意义。对象初始值设定项语法只是语法糖的简写。

这:

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

您可以让 DoSomething 方法验证它是否具有完成其工作所需的信息,而不是依赖于显式属性来告诉您对象何时初始化。你的例子很粗糙,我希望你的实际实现更复杂,所以我只是假设必须将Property1Property2分配给某些东西(这意味着在继续之前不是一个空字符串(:

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

这可以很容易地更改以适应FooFooConfig上的构造函数使用。

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

如果您希望对象的状态依赖于要初始化的特定属性集,则可以将代码添加到每个属性的 setter 中,并在内部对其进行跟踪。 不过,这实际上取决于您要实现的目标。

更新

只是阅读您对@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";

跟踪单个属性 setter 的执行并不难,并在除第一次执行之外的所有执行中触发一些副作用,但要说我只想在客户端更改初始对象配置时触发副作用在 ctor 完成后毫无意义。