C# nested object initializer - c#

C# 5.0 Language Specification 7.6.10.2 Object initializers states that
A member initializer that specifies an object initializer after the
equals sign is a nested object initializer, i.e. an initialization of
an embedded object. Instead of assigning a new value to the field or
property, the assignments in the nested object initializer are treated
as assignments to members of the field or property. Nested object
initializers cannot be applied to properties with a value type, or to
read-only fields with a value type.
While I understand read-only fields cannot be modified by the initializers after the constructor is run, I do not have a clue about the restriction on properties.
The following is a code sample I used to test this restriction on properties:
using System;
namespace ObjectCollectionInitializerExample
{
struct MemberStruct
{
public int field1;
public double field2;
}
class ContainingClass
{
int field;
MemberStruct ms;
public int Field
{
get { return field; }
set { field = value; }
}
public MemberStruct MS
{
get { return ms; }
set { ms = value; }
}
}
class Program
{
static void Main(string[] args)
{
// Nested object initializer applied to a property of value type compiles!
ContainingClass cc = new ContainingClass { Field = 1, MS = new MemberStruct { field1 = 1, field2 = 1.2} };
Console.ReadKey();
}
}
}
I commented on the code where it was supposed to generate a compiler error based on the specification. But it compiles successfully. What am I missing here?
Thanks

What you have is not a nested object initializer because you explicitly create a new instance of MemberStruct. The inner object initializer doesn't directly follow the equals sign, but is an object initializer on its own associated with the call to the MemberStruct constructor.
This is how using a nested object initializer would look like:
ContainingClass cc = new ContainingClass { Field = 1, MS = { field1 = 1, field2 = 1.2} };
This will not compile when MS is a value type (struct), but it will compile when MS is a reference type (object).

Related

What is happening with this C# object initializer code?

What is going on with this C# code? I'm not even sure why it compiles. Specifically, what's going on where it's setting Class1Prop attempting to use the object initializer syntax? It seems like invalid syntax but it compiles and produces a null reference error at runtime.
void Main()
{
var foo = new Class1
{
Class1Prop =
{
Class2Prop = "one"
}
};
}
public class Class1
{
public Class2 Class1Prop { get; set; }
}
public class Class2
{
public string Class2Prop { get; set; }
}
This is allowed by object initializer syntax in the C# specification, where it is called a nested object initializer. It is equivalent to:
var _foo = new Class1();
_foo.Class1Prop.Class2Prop = "one"
var foo = _foo;
It should be a little more obvious why this throws a null reference exception. Class1Prop was never initialized in the constructor of Class1.
The benefit of this syntax is that the caller can use the convenient object initializer syntax even when the properties are getter-only to set mutable properties on nested objects. For example, if Class1Prop was a getter-only property the example is still valid.
Note that there is an inaccessible temporary variable created to prevent the access of a field or array slot before the full initialization has run.

Why does this nested object initializer throw a null reference exception?

The following testcase throws a null-reference exception, when it tries to assign Id to an object which is null, since the code is missing the "new R" before the object initializer.
Why is this not caught by the compiler? Why is it allowed, in which use-cases would this be a meaningful construct?
[TestClass]
public class ThrowAway
{
public class H
{
public int Id { get; set; }
}
public class R
{
public H Header { get; set; }
}
[TestMethod]
public void ThrowsException()
{
var request = new R
{
Header =
{
Id = 1
},
};
}
}
The compiler doesn't give a warning because you could have:
public class R
{
public H Header { get; set; }
public R()
{
Header = new H();
}
}
so Header could be initialized by someone/something. Solving if someone/something will initialize Header is a complex problem (probably similar to the Halting problem)... Not something that a compiler wants to solve for you :-)
From the C# specifications:
A member initializer that specifies an object initializer after the equals sign is a nested object initializer, i.e. an initialization of an embedded object. Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.
We are in the case of nested initializer, and see the bolded part. I didn't know it.
Now, note that new R { } is, by C# spec, an 7.6.10.1 Object creation expressions followed by an object-initializer, while the Header = { } is a "pure" 7.6.10.2 Object initializers.

Invalid initializer member class with enum

I have a class and enum,how can I initilize like this way, my initializer,
SkSqlPamameter prm = new SkSqlPamameter
{
ParameterName = "#param1",
Value = "param1", SkSqlDbType.Int
};
and class and enum;
enum SkSqlDbType
{
Int,
Nvarchar,
Date,
Bool,
Decimal,
Double
}
public class SkSqlPamameter
{
public string ParameterName;
public SkSqlDbType SkDbType;
public string Value;
}
SkSqlPamameter prm = new SkSqlPamameter
{
ParameterName = "#param1",
Value = "param1",
SkDbType = SkSqlDbType.Int // you missed property name here
};
Object initializer contains member initializers, which should look like identifier = initializer-value. From C# specification 7.6.10.2 Object initializers:
Each member initializer must name an accessible field or property of
the object being initialized, followed by an equals sign and an
expression or an object initializer or collection initializer.

Set value of a Nested field in reflection

in my application that uses reflection i have two classes
public class FirstClass
{
public string someVar;
public SecondClass second;
public FirstClass()
{
second = new SecondClass();
}
}
public class SecondClass
{
public string anotherVar;
}
in my main program i have an instance of FirstClass
MainProgram()
{
Object obj = InstanceOfFirstClass() // reflected instance of first class
}
How do i set the value of anotherVar inside obj?
With public fields, this is relatively simple:
object obj = InstanceOfFirstClass();
object second = obj.GetType().GetField("second").GetValue(obj);
second.GetType().GetField("anotherVar").SetValue(second, "newValue");
If the fields were not public, then you would need to use an overload of GetField that takes a BindingFlags argument with the NonPublic flag set.
In .Net 4, you could just use dynamic:
dynamic obj = InstanceOfFirstClass();
obj.second.anotherVar = "newValue";
You can find the example which reads the field and set a value of the field via reflection in
http://msdn.microsoft.com/en-us/library/6z33zd7h.aspx.
In your case it will look like
Object myObject = InstanceOfFirstClass() // reflected instance of first class
Type myType = typeof(FirstClass);
FieldInfo myFieldInfo = myType.GetField("second",
BindingFlags.Public | BindingFlags.Instance);
// Change the field value using the SetValue method.
myFieldInfo.SetValue(myObject , //myobject is the reflected instance
value);//value is the object which u want to assign to the field);

Assignment to readonly property in initializer list

Can one tell me, why the heck does it compile?
namespace ManagedConsoleSketchbook
{
public interface IMyInterface
{
int IntfProp
{
get;
set;
}
}
public class MyClass
{
private IMyInterface field = null;
public IMyInterface Property
{
get
{
return field;
}
}
}
public class Program
{
public static void Method(MyClass #class)
{
Console.WriteLine(#class.Property.IntfProp.ToString());
}
public static void Main(string[] args)
{
// ************
// *** Here ***
// ************
// Assignment to read-only property? wth?
Method(new MyClass { Property = { IntfProp = 5 }});
}
}
}
This is a nested object initializer. It's described in the C# 4 spec like this:
A member initializer that specifies an object initializer after the equals sign is a nested object initializer - that is, an initialization of an embedded object. Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.
So this code:
MyClass foo = new MyClass { Property = { IntfProp = 5 }};
would be equivalent to:
MyClass tmp = new MyClass();
// Call the *getter* of Property, but the *setter* of IntfProp
tmp.Property.IntfProp = 5;
MyClass foo = tmp;
Because you are using the initializer which uses the setter of ItfProp, not the setter of Property.
So it will throw a NullReferenceException at runtime, since Property will still be null.
Because
int IntfProp {
get;
set;
}
is not readonly.
You did not invoke setter of MyClass.Property, just getter.

Categories

Resources