Readonly field in object initializer

余生颓废 提交于 2019-12-10 03:34:08

问题


I wonder why it is not possible to do the following:

struct TestStruct
{
    public readonly object TestField;
}

TestStruct ts = new TestStruct {
    /* TestField = "something" // Impossible */
};

Shouldn't the object initializer be able to set the value of the fields ?


回答1:


Object Initializer internally uses a temporary object and then assign each value to the properties. Having a readonly field would break that.

Following

TestStruct ts = new TestStruct 
{
     TestField = "something";
};

Would translate into

TestStruct ts;
var tmp = new TestStruct();
tmp.TestField = "something"; //this is not possible
ts = tmp;

(Here is the answer from Jon Skeet explaining the usage of temporary object with object initalizer but with a different scenario)




回答2:


readonly means that the field can only be set in the constructor (or in a field initializer). Properties specified in the object initializer are set after the constructor has returned. That is,

TestStruct ts = new TestStruct {
    TestField = "something"
};

is basically equivalent to

TestStruct ts = new TestStruct();
ts.TestField = "something";

(In a Debug build, the compiler may use a temporary variable, but you get the idea.)




回答3:


This is not possible. since readonly fields cannot be assigned from other than Constructor or Field Initializer.

What you show is actually object initializer. It is just a syntatic sugar, gets comiled into something like this

TestStruct ts;
TestStruct ts1 = new TestStruct();
ts1.TestField = value;
ts = ts1;

Is that clear why it doesn't compile?




回答4:


I wonder why it is not possible to do the following:

Because the compiler cannot know for sure that the following code will be executed:

TestStruct ts = new TestStruct 
{
    TestField = "something"
};

You should initialize readonly members directly inline or inside the constructor.




回答5:


From MSDN:

The readonly keyword is a modifier that you can use on fields. When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class.

So it's simply not (yet) possible since object initializers are just post-creation assignments.




回答6:


Because object initializer is just a short way of initializing:

TestStruct ts = new TestStruct {
  TestField = "something";
};

is the same to (compiler will translate the above to this):

TestStruct ts = new TestStruct();
ts.TestField = "something";//this is of course not allowed.



回答7:


I ran across an interesting "exception" to this, in the case where the readonly field extends CollectionBase.

Here's the code:

using System.Collections;

namespace ReadOnly
{
    class Program
    {
        static void Main(string[] args)
        {
            Foo foo1 = new Foo()
            {
                Bar = new Bar()  // Compile error here - readonly property.
                {
                    new Buzz() { Name = "First Buzz" }
                }
            };

            Foo foo2 = new Foo()
            {
                Bar = // No Compile error here.
                {
                    new Buzz { Name = "Second Buzz" }
                }
            };
        }
    }

    class Foo
    {
        public Bar Bar { get; }
    }

    class Bar : CollectionBase
    {
        public int Add(Buzz value)
        {
            return List.Add(value);
        }

        public Buzz this[int index]
        {
            get { return (Buzz)List[index]; }
            set { List[index] = value; }
        }
    }

    class Buzz
    {
        public string Name { get; set; }
    }
}

Foo1 is how I initially tried to do it (all these classes came from an external library so we didn't know at first that Bar was readonly). Got the compile error. Then accidentally I retyped it like foo2, and it worked.

After decompiling the dll and seeing that Bar extended CollectionBase, we realized that the second syntax (foo2) was invoking the Add method on the collection. So, in the case of collections, while you can't set a read only property, you can invoke the Add method, via object initializers.



来源:https://stackoverflow.com/questions/18385248/readonly-field-in-object-initializer

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!