这样的对象可以被认为是不可变的吗?

时间:2011-06-25 08:25:56

标签: .net immutability

我设计了一个类,其中包含有关将在SQL Server数据库中注册的给定对象的一些信息。我想使这个对象(深度)不可变,但我也必须保证它只被注册一次。如果此对象实现以下模式,它仍然可以被视为不可变吗?

public class NewClass
{
    private bool registered;

    public string SomeProperty { get; private set; }

    public NewClass Register()
    {
        if (registered)
        {
            throw new NotImplementedException(/*arguments*/);
        }

        /* Register on DB here... */
        registered = true;
        return new NewClass(somePropertyFromDB);
    }

    public NewClass(string someProperty)
    {
        registered = false;
        SomePropery = someproperty;
    }
}

我会说,除了布尔字段registered之外,对象是不可变的,但是这个字段让我有些怀疑,因为它会在第一次执行Register方法时实际发生变化...任何人都可以告诉我如何解决这个问题仍然使对象不可变?

1 个答案:

答案 0 :(得分:3)

不,它肯定是不可变的。 registered值会在对象的生命周期内发生变化。

要使其不可变,您不能允许registered字段更改对象的生命周期 - 而是让Register返回一个值true的新对象registered

我还会移除SomeProperty的私有设置器,只有一个getter和一个只读变量。

这样的事情:

public class NewClass
{
    private readonly bool registered;
    private readonly string someProperty;

    public bool Registered { get { return registered; } }
    public string SomeProperty { get { return someProperty; } }

    public NewClass Register()
    {
        // Note the change of exception here
        if (registered)
        {
            throw new InvalidOperationException("Already registered");
        }

        return new NewClass(somePropertyFromDB, true);
    }

    // You may want to have a public constructor with just someProperty
    // which calls this one, which you could make private
    public NewClass(string someProperty, bool registered)
    {
        this.registered = registered.;
        this.someProperty = someproperty;
    }
}

一些注意事项:

  • 另一种选择是拥有两个单独的类RegisteredFooUnregisteredFoo;这可能会使用这个类更容易理解代码
  • 没有什么可以阻止某人两次调用Register,所以使这种不可变性在幂等性方面并没有真正帮助。由于存在一种自然的副作用(与数据库交谈),因此很难使其真正发挥作用。