问题
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
readonlykeyword 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