使用C#中的默认构造函数初始化readonly成员变量

时间:2011-05-31 20:47:54

标签: c# generics readonly

我的代码中有一个简单的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;,则工厂不能再在构造时设置它的值。

我通常通过提供参数化构造函数来解决这个问题,但这会破坏通用实现,因为AFAIK where T : new()意味着无参数构造函数。

我可能只是错过了一些我的C#chops的齿轮,但是实现这样的东西最好的方法是什么? (或者最好放弃readonly并相信代码不会以不安全的方式修改parent --- NullReferenceException会浮现在脑海中...... )

3 个答案:

答案 0 :(得分:4)

您可以使用反射来设置字段,无论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;
    }
}

答案 1 :(得分:4)

我认为你不能准确获得你想要的东西,但你可以制作一个只可分配一次的属性,让工厂覆盖它。但我想用户总是可以强制覆盖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;
        }
    }

创建它之后,我搜索并找到了一个可能比我更好的答案:Is there a way of setting a property once only in C#

答案 2 :(得分:0)

我不确定这是否正是您想要的,但我想出了一种方法,用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();
}