使用C#中的默认构造函数初始化只读成员变量
本文关键字:初始化 只读 成员 变量 构造函数 默认 使用 | 更新日期: 2023-09-27 17:58:10
我的代码中有一个简单的Factory实现。我的目标是让构建的对象保留对创建它们的工厂的引用,所以我把它们连接起来,类似于这样:
public class Factory {
public T CreateObject<T>() where T : Foo, new()
{
return new T() {
parent = this
};
}
}
public class Foo {
internal Factory parent;
internal Foo() { }
}
这读起来很有效,但我一直在想,我可能想要parent
变量,这样一旦工厂设置了它,就不能更改它。然而,如果我像internal readonly Factory parent;
一样声明它,那么工厂就不能再在构造中设置它的值了。
我通常会通过提供一个带参数的构造函数来弥补这一点,但这会扼杀通用实现,因为AFAIKwhere T : new()
意味着一个无参数的构造函数。
我可能只是缺少了一些C#技巧,但实现这样的东西的最佳方法是什么?(还是最好放弃readonly
,并相信代码不会以不安全的方式修改parent
---想到NullReferenceException
---?)
我不认为你可以获得你想要的东西,但你可以创建一个只能赋值一次的属性,并让工厂覆盖它。但我想用户总是可以用new CreatingFactory
强制覆盖,但我认为这会让它变得困难,至少可以清楚地表明你的意图。
你可以做下面这样的事情。
class Foo
{
private Factory factory;
public Factory CreatingFactory
{
get { return factory; }
set
{
if (factory != null)
{
throw new InvalidOperationException("the factory can only be set once");
}
factory = value;
}
}
}
class Factory
{
public T Create<T>()
where T : Foo, new()
{
T t = new T()
{
CreatingFactory = this
};
return t;
}
}
创建后,我搜索并找到了一个可能比我更好的答案:有没有一种方法可以只在C#中设置一次属性
您可以使用反射来设置字段,这将在不考虑readonly
修饰符的情况下工作:
public class Factory
{
public T CreateObject<T>() where T : Foo, new()
{
T t = new T();
t.GetType()
.GetField("parent", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(t, this);
return t;
}
}
我不确定这是否正是您想要的,但我提出了一种方法,用Func
替换您的泛型类型参数,该方法显示了如何构造Foo
对象,并允许您在构造函数中设置父对象。
public class Factory {
private Func<Factory, Foo> creator;
public Factory(Func<Factory, Foo> creator) {
this.creator = creator;
}
public Foo CreateObject()
{
return this.creator(this);
}
}
public class Foo {
internal readonly Factory parent;
internal Foo(Factory parent) {
this.parent = parent;
}
}
然后
public void Main() {
Factory myfactory = new Factory(fact => new Foo(fact));
Foo myfoo = myfactory.CreateObject();
}