[英]Initializing a readonly member variable with a default constructor in C#
I have a simple Factory implementation in my code.我的代码中有一个简单的工厂实现。 I'm aiming to have the constructed objects retain a reference to the factory that created them, so I have them wired up similar to this:
我的目标是让构造的对象保留对创建它们的工厂的引用,因此我将它们连接起来类似于:
public class Factory {
public T CreateObject<T>() where T : Foo, new()
{
return new T() {
parent = this
};
}
}
public class Foo {
internal Factory parent;
internal Foo() { }
}
This works as it reads, but I've been thinking that I probably want that parent
variable so that it cannot be changed once it's set by the factory.这就像它所读的那样有效,但我一直在想我可能想要那个
parent
变量,这样一旦工厂设置它就不能改变它。 However, if I declare it like internal readonly Factory parent;
但是,如果我将其声明为
internal readonly Factory parent;
, then the factory can't set it's value anymore on construction. ,那么工厂就不能再在施工时设定它的价值了。
I'd normally remedy this by providing a parametered constructor, but that kills the generic implementation, because AFAIK where T: new()
implies a parameter-less constructor.我通常会通过提供一个带参数的构造函数来解决这个问题,但这会杀死通用实现,因为 AFAIK
where T: new()
意味着一个无参数的构造函数。
I may just be missing a few cogs with my C# chops, but what would be the best way to go about implementing something like this?我的 C# 排骨可能只是缺少一些齿轮,但是对于 go 实施这样的事情,最好的方法是什么? (Or would it be better to just ditch the
readonly
and trust that the code won't be modifying parent
in an unsafe manner --- NullReferenceException
s come to mind ---?) (或者最好放弃
readonly
并相信代码不会以不安全的方式修改parent
--- NullReferenceException
s会浮现在脑海中---?)
You could use reflection to set the field, this will work regardless of the readonly
modifier:您可以使用反射来设置字段,无论
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;
}
}
I do not think you can obtain exactly what you want, but you could make a property that is only assignable once and let the factory overwrite it.我不认为你能得到你想要的东西,但你可以创建一个只能分配一次的属性,然后让工厂覆盖它。 But I guess the user can always force an override with
new CreatingFactory
, but I think this makes it difficult and at least clearly shows your intention.但我想用户总是可以用
new CreatingFactory
强制覆盖,但我认为这使它变得困难并且至少清楚地表明了你的意图。
You could do something like below.您可以执行以下操作。
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;
}
}
After having created it i searched and found an answer that is probably better than mine: Is there a way of setting a property once only in C#创建它后,我搜索并找到了一个可能比我更好的答案: Is there a way to set a property only in C#
I'm not sure if this is exactly what you want, but I came up with an approach that replaces your generic type parameter with a Func
that shows how to construct the Foo
object and allows you to set the parent in the constructor.我不确定这是否正是您想要的,但我想出了一种方法,用
Func
替换您的泛型类型参数,该方法显示如何构造Foo
object 并允许您在构造函数中设置父级。
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;
}
}
and then接着
public void Main() {
Factory myfactory = new Factory(fact => new Foo(fact));
Foo myfoo = myfactory.CreateObject();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.