我有一个不可变对象的尝试:
class MyObject
{
private static int nextId;
public MyObject()
{
_id = ++nextId;
}
private int _id;
public int Id { get { return _id; } }
public string Name { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
然后,我试着像这样使用它:
MyObject o1 = new MyObject { Name = "foo" };
Run Code Online (Sandbox Code Playgroud)
但是对象初始化器失败了,因为它Name的setter是私有的.有没有办法解决这个问题,还是我必须在一个或另一个之间做出选择?
Bry*_*tts 26
您不能将对象初始值设定项与不可变对象一起使用.它们需要可设置的属性.
不可变对象意味着"创建后不会改变".使Name构造函数参数整齐地表达该原则.
如果对象对于可理解的构造函数来说太复杂,您还可以使用Builder模式.通常,构建器本身将具有可变属性(可以在对象初始化器中使用),并且其.Build()方法将创建实际实例.
编辑(OP):我将添加我自己在这里制作的建筑师的例子,然后接受这个答案,因为它提出了一个合理的解决方案.
class MyObject
{
public class Builder
{
public Builder()
{
// set default values
Name = String.Empty;
}
public MyObject Build()
{
return new MyObject(Name);
}
public string Name { get; set; }
}
private static int nextId;
protected MyObject(string name)
{
Id = ++nextId;
Name = name;
}
public int Id { get; private set; }
public string Name { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用以下内容构造它的实例:
MyObject test = new MyObject.Builder { Name = "foo" }.Build();
Run Code Online (Sandbox Code Playgroud)
编辑:这是我对模式的看法:
public abstract class Builder<T>
{
public static implicit operator T(Builder<T> builder)
{
return builder.Build();
}
private bool _built;
public T Build()
{
if(_built)
{
throw new InvalidOperationException("Instance already built");
}
_built = true;
return GetInstance();
}
protected abstract T GetInstance();
}
Run Code Online (Sandbox Code Playgroud)
以下是您实施的示例Builder<T>.它利用嵌套类型的作用域规则来访问私有setter:
public class MyObject
{
private static int nextId;
protected MyObject()
{
Id = ++nextId;
}
public int Id { get; private set; }
public string Name { get; private set; }
public sealed class Builder : Builder<MyObject>
{
private MyObject _instance = new MyObject();
protected override MyObject GetInstance()
{
// Validate properties here
return _instance;
}
public string Name
{
get { return _instance.Name; }
set { _instance.Name = value; }
}
}
}
Run Code Online (Sandbox Code Playgroud)
它具有对目标类型的隐式转换,允许您执行以下操作:
MyObject myObject = new MyObject.Builder { Name = "Some name" };
Run Code Online (Sandbox Code Playgroud)
或这个:
public void Foo(MyObject myObject)
// ...
Foo(new MyObject.Builder { Name = "Some name" });
Run Code Online (Sandbox Code Playgroud)
您需要在构造函数中设置属性,并且您不需要id的单独局部变量:
class MyObject {
private static int nextId = 0;
public MyObject(string name) {
Id = ++nextId;
Name = name;
}
public int Id { get; private set; }
public string Name { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
创建:
MyObject o1 = new MyObject("foo");
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2611 次 |
| 最近记录: |