Why is `this` not available in C# 6.0 Auto-Property Initialization? - c#

I have the following code class:
public class Foo
{
public Nested Bar { get; } = new Nested(this);
public class Nested
{
public Nested(Foo foo)
{
foo.DoSomething();
}
}
private void DoSomething()
{
}
}
However, I get this compile error:
Keyword 'this' is not available in the current context
I can fix it by simply not using Auto-Property Initializer, and explicitly move it into a constructor instead:
public Nested Bar { get; }
public Foo()
{
this.Bar = new Nested(this);
}
Why is it so? Isn't Auto-Property Initializer actually translated into constructor code in IL?

Simply: you can't use this in initializers. The idea is to prevent an incomplete object from escaping - Nested(this) could do anything to your object, leading to very confusing and hard to understand bugs. Keep in mind that initializers execute before any constructor that you add. The same thing fails for field initializers too, in exactly the same way:
private Nested _field = new Nested(this);
Essentially, initializers are intended to perform simple initializations - fixing the 98% problem. Anything involving this is more complex, and you'll need to write your own constructor - and take the blame for any timing issues :)

Why is it so? Isn't Auto-Property Initializer actually translated into constructor code in IL?
The rules for automatically implemented property initializers are the same as those for field initializers, for the same reason. Note that property initializers are executed before base class bodies, just like field initializers - so you're still in the context of a "somewhat uninitialized" object; more so than during a constructor body.
So you should imagine that the property is being converted into this:
private readonly Nested bar = new Nested(this); // Invalid
public Nested Bar
{
get { return bar; }
}
In short, this restriction is to stop you from getting yourself into trouble. If you need to refer to this when initializing a property, just do it manually in a constructor, as per your second example. (It's relatively rare in my experience.)

Related

Property initializers vs old way of initializing property .Can you clarify

googled but could not find an explanation of usage for property initializers
Could somebody tell me if below code is the same?are properties that uses property initializers only instantied once?
what is the difference between these 3 ways of initialize a list in terms of efficiency and best practice
1) private List<Address>Addresses
{
get
{
return addresses ?? (addresses = new List<Address>());
}
}
2) public List<Address> Addresses{ get; set; } = new List<Address>();
3) within constructor Addresses= new List<Address>()
thanks for clarifation!
Examples 2 and 3 initialize the property as soon as each instance is created.
Example 1 initializes the property lazily; it does this by initializing the backing field only at the first invocation of the property getter (when the backing field is still uninitialized). It's entirely possible that the backing field remains uninitialized for the entire lifetime of a given instance provided that instance's Addresses property is never accessed.
Whether or not lazy initialization is more efficient depends entirely on the property and how it's going to be used.
The pre-C# 6 equivalent of example 2 is not lazy initialization, but the following:
public List<Address> Addresses { get; set; }
... with initialization being done in the constructor. Declaring and initializing an auto-implemented property in the same statement is new to C# 6.
First of all, do not use concrete implementation of class for property, use interface (IList, for example). Secondly, I prefer to initialize property as your Addresses inside default constructor and then call this constructor from another.
For example:
public class MyClass1
{
public IList<MyPropertyClass1> Property1{get; protected set;}
public MyPropertyClass2 Property2{get; protected set;}
...
public MyClass1()
{
//I initialize Property1 by empty List<T>=> internal logic will not crashed if user try to set Property1 as null.
Property1=new List<MyPropertyClass1>();
Property2=default(MyPropertyClass2);
...
}
public MyClass1(IList<MyPropertyClass1> property1, MyPropertyClass2 property2)
:this()
{
if(property1!=null)
{
Property1=property1;
}
if(property2!=default(MyPropertyClass2))
{
Property2=property2;
}
}
}

Understanding C# field initialization requirements

Considering the following code:
public class Progressor
{
private IProgress<int> progress = new Progress<int>(OnProgress);
private void OnProgress(int value)
{
//whatever
}
}
This gives the following error on compilation:
A field initializer cannot reference the non-static field, method, or property 'Progressor.OnProgress(int)'
I understand the restriction it is complaining about, but I don't understand why it is an issue, but the field can be initialized in the constructor instead as follows:
public class Progressor
{
private IProgress<int> progress;
public Progressor()
{
progress = new Progress<int>(OnProgress);
}
private void OnProgress(int value)
{
//whatever
}
}
What is the difference in C# regarding the field initialization vs constructor initialization that requires this restriction?
Field initialization come before base class constructor call, so it is not a valid object. Any method call with this as argument at this point leads to unverifiable code and throws a VerificationException if unverifiable code is not allowed. For example: in security transparent code.
10.11.2 Instance variable initializers
When an instance constructor has no constructor initializer, or it has a constructor initializer of the form base(...), that constructor implicitly performs the initializations specified by the variable-initializers of the instance fields declared in its class. This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor and before the implicit invocation of the direct base class constructor. The variable initializers are executed in the textual order in which they appear in the class declaration.
10.11.3 Constructor execution
Variable initializers are transformed into assignment statements, and these assignment statements are executed before the invocation of the base class instance constructor. This ordering ensures that all instance fields are initialized by their variable initializers before any statements that have access to that instance are executed.
Everything in my answer is just my thoughts on 'why it would be dangerous to allow that kind of access'. I don't know if that's the real reason why it was restricted.
C# spec says, that field initialization happens in the order fields are declared in the class:
10.5.5.2. Instance field initialization
The variable initializers are executed in the textual order in which
they appear in the class declaration.
Now, let's say the code you've mentioned is possible - you can call instance method from field initialization. It would make following code possible:
public class Progressor
{
private string _first = "something";
private string _second = GetMyString();
private string GetMyString()
{
return "this is really important string";
}
}
So far so good. But let's abuse that power a little bit:
public class Progressor
{
private string _first = "something";
private string _second = GetMyString();
private string _third = "hey!";
private string GetMyString()
{
_third = "not hey!";
return "this is really important string";
}
}
So, _second get's initialized before _third. GetMyString runs, _third get's "not hey!" value assigned, but later on it's own field initialization runs, and it's being set to `"hey!". Not really useful nor readable, right?
You could also use _third within GetMyString method:
public class Progressor
{
private string _first = "something";
private string _second = GetMyString();
private string _third = "hey!";
private string GetMyString()
{
return _third.Substring(0, 1);
}
}
What would you expect to be value of _second? Well, before field initialization runs all the fields get default values. For string it would be null, so you'll get unexpected NullReferenceException.
So imo, designers decided it's just easier to prevent people from making that kind of mistakes at all.
You could say, OK let's disallow accessing properties and calling methods, but let's allow using fields that were declared above the one you want to access it from. Something like:
public class Progressor
{
private string _first = "something";
private string _second = _first.ToUpperInvariant();
}
but not
public class Progressor
{
private string _first = "something";
private string _second = _third.ToUpperInvariant();
private string _third = "another";
}
That's seems useful and safe. But there is still a way to abuse it!
public class Progressor
{
private Lazy<string> _first = new Lazy<string>(GetMyString);
private string _second = _first.Value;
private string GetMyString()
{
// pick one from above examples
}
}
And all the problems with methods happen to come back again.
Section 10.5.5.2: Instance field initialization describes this behavior:
A variable initializer for an instance field cannot reference the
instance being created. Thus, it is a compile-time error to reference
this in a variable initializer, as it is a compile-time error for a
variable initializer to reference any instance member through a
simple-name
This behavior applies to your code because OnProgress is an implicit reference to the instance being created.
The answer is more or less, the designers of C# preferred it that way.
Since all field initializers are translated into instructions in the constructor(s) which go before any other statements in the constructor, there is no technical reason why this should not be possible. So it is a design choice.
The good thing about a constructor is that it makes it clear in what order the assignments are done.
Note that with static members, the C# designers chose differently. For example:
static int a = 10;
static int b = a;
is allowed, and different from this (also allowed):
static int b = a;
static int a = 10;
which can be confusing.
If you make:
partial class C
{
static int b = a;
}
and elsewhere (in other file):
partial class C
{
static int a = 10;
}
I do not even think it is well-defined what will happen.
Of course for your particular example with delegates in an instance field initializer:
Action<int> progress = OnProgress; // ILLEGAL (non-static method OnProgress)
there is really no problem since it is not a read or an invocation of the non-static member. Rather the method info is used, and it does not depend on any initialization. But according to the C# Language Specification it is still a compile-time error.

Object Initializers, Non-Public Children, and Nested Initialization

I was looking through my codebase and found a line of code that R# had helpfully refactored for me. Here's a representative sample:
public class A
{
public B Target { get; private set; }
public object E { get; set; }
public A()
{
Target = new B();
}
}
public class B
{
public object C { get; set; }
public object D { get; set; }
}
public static class Test
{
static A LocalA;
static void Initialize()
{
LocalA = new A
{
E = "obviously this should be settable",
Target =
{
C = "Whoah, I can set children properties",
D = "without actually new-ing up the child object?!"
}
};
}
}
Essentially, initialization syntax allows for setting a child object's public properties without actually performing the constructor call (obviously if I pull the Target constructor call from the constructor of A, the whole initialization fails due to a null reference.
I've searched for this, but it's difficult to put into Google-able terms. So, my question is: (a) what is this called exactly, and (b) where can I find some more information in C# documentation about it?
Edit
Looks like someone else has asked this with similar lack of documentation found:
Nested object initializer syntax
There is nothing concrete in the documentation that I see on this topic of Object Initializers, but I did decompile the code, and here is what it actually looks like once decompiled:
A a = new A();
a.E = "obviously this should be settable";
a.Target.C = "Whoah, I can set children properties";
a.Target.D = "without actually new-ing up the child object?!";
Test.LocalA = a;
A known fact on Object Initializers is that they always run the constructor first. So, that makes the above code work. If you remove the initialization of Target in the constructor of A you will get an exception when the property initializers are tried since the object was never instantiated.
This might not be the answer and I agree its really difficult to put this into a language that google understands
In this case you are assigning values to C and D which are public properties of Target object
LocalA.Target.C = "Whoah, I can set children properties";
LocalA.Target.D = "without actually new-ing up the child object?! Nope I dont think so:)!"
You are not actually initializing a new B() as the Target setter is Private. This is obviously going to fail if B is not initialized.

Can I use Object Initialization Syntax to assign values to properties before the constructor runs?

I am serializing objects to XML using System.Xml.Serialization and this requires me to have parameterless constructors.
I am therefore trying to use Object Initialization Syntax to assign values to certain properties and then use the constructor logic to format these values as needs be before I serialize the objects to XML.
My problem is that the constructor runs before the properties are assigned their values. A simplified example is below:
class Program
{
static void Main(string[] args)
{
Foo myFoo = new Foo() { HelloWorld = "Beer", HelloWorldAgain = "More beer" };
Console.WriteLine(myFoo.HelloWorld);
Console.WriteLine(myFoo.HelloWorldAgain);
Console.ReadLine();
}
}
public class Foo : Bar
{
public string HelloWorld { get; set; }
public Foo()
{
Console.WriteLine("Foo Was Initialized");
Console.WriteLine(HelloWorld);
}
}
public abstract class Bar
{
public string HelloWorldAgain { get; set; }
public Bar()
{
Console.WriteLine("Bar was initialized");
Console.WriteLine(HelloWorldAgain);
}
}
This results in the following output:
As you can see the constructor logic runs, and then the properties are assigned values. I need this to work the other way around.
Is this possible?
Serialization requires you to have a parameterless constructor, but does not limit you to that one constructor.
Keep the no-arg constructor for deserialization, but add another constructor that takes your values and does the required initialization when you need to instantiate the class in code.
Object initialization syntax is just shorthand for setting properties after construction.
No. Object initialization syntax is just a shortcut. When you write:
Foo foo = new Foo { HelloWorld = "Beer" };
The compiler just rewrites this to something very close to what happens if you write:
Foo foo = new Foo();
foo.HelloWorld = "Beer";
If the parameters are required in order for your object to exist, you should put them as arguments in the constructor.
No it's not possible, cause in order to be able to initialize a property of the object, object has already exist. It's existance is guranteed by ctor running before all other stuff.
If we are talking about "not running default constructor", like a conceptual question.
You can do that by using a static property. In that case Foo() will not be called. But it's naturally out of the current question subject.
Arguably, the syntax is deceptive. What is happening here?
var myFoo = new Foo();
myFoo.HelloWorld = "Beer";
myFoo.HelloWorldAgain = "MoreBeer";
That's it, I'm afraid. It's simply not possible to initialise properties before the constructor has run. The constructor is the first thing that 'happens' after memory for the object is allocated and default values are assigned to fields.
BTW, you don't need the parens using the object initialisation syntax. This would be just as good (but even more deceptive):
var myFoo = new Foo { HelloWorld = "Beer", HelloWorldAgain = "MoreBeer" };
Looking at your question, it looks like what you're trying to do (modify the properties before serialisation) doesn't belong in the constructor.

What's the difference between an object initializer and a constructor?

What are the differences between the two and when would you use an "object initializer" over a "constructor" and vice-versa? I'm working with C#, if that matters. Also, is the object initializer method specific to C# or .NET?
Object Initializers were something added to C# 3, in order to simplify construction of objects when you're using an object.
Constructors run, given 0 or more parameters, and are used to create and initialize an object before the calling method gets the handle to the created object. For example:
MyObject myObjectInstance = new MyObject(param1, param2);
In this case, the constructor of MyObject will be run with the values param1 and param2. These are both used to create the new MyObject in memory. The created object (which is setup using those parameters) gets returned, and set to myObjectInstance.
In general, it's considered good practice to have a constructor require the parameters needed in order to completely setup an object, so that it's impossible to create an object in an invalid state.
However, there are often "extra" properties that could be set, but are not required. This could be handled through overloaded constructors, but leads to having lots of constructors that aren't necessarily useful in the majority of circumstances.
This leads to object initializers - An Object Initializer lets you set properties or fields on your object after it's been constructed, but before you can use it by anything else. For example:
MyObject myObjectInstance = new MyObject(param1, param2)
{
MyProperty = someUsefulValue
};
This will behave about the same as if you do this:
MyObject myObjectInstance = new MyObject(param1, param2);
myObjectInstance.MyProperty = someUsefulValue;
However, in multi-threaded environments the atomicity of the object initializer may be beneficial, since it prevents the object from being in a not-fully initialized state (see this answer for more details) - it's either null or initialized like you intended.
Also, object initializers are simpler to read (especially when you set multiple values), so they give you the same benefit as many overloads on the constructor, without the need to have many overloads complicating the API for that class.
A constructor is a defined method on a type which takes a specified number of parameters and is used to create and initialize an object.
An object initializer is code that runs on an object after a constructor and can be used to succinctly set any number of fields on the object to specified values. The setting of these fields occurs after the constructor is called.
You would use a constructor without the help of an object initializer if the constructor sufficiently set the initial state of the object. An object initializer however must be used in conjunction with a constructor. The syntax requires the explicit or implicit use (VB.Net and C#) of a constructor to create the initial object. You would use an object initializer when the constructor does not sufficiently initialize the object to your use and a few simple field and/or property sets would.
When you do
Person p = new Person { Name = "a", Age = 23 };
this is what an object initializer essentially does:
Person tmp = new Person(); //creates temp object calling default constructor
tmp.Name = "a";
tmp.Age = 23;
p = tmp;
Now this facilitates behaviour like this. Knowing how object initializers work is important.
If you have properties that MUST be set on your object for it to work properly, one way is to expose just a single constructor which requires those mandatory properties as parameters.
In that case, you cannot create your object without specifying those mandatory properties. Something like that cannot be enforced by object initializers.
Object initializers are really just a "syntax convenience" to shorten initial assignments. Nice, but not really very functionally relevant.
Marc
A constructor is a method (possibly) accepting parameters and returning a new instance of a class. It may contain initialization logic.
Below you can see an example of a constructor.
public class Foo
{
private SomeClass s;
public Foo(string s)
{
s = new SomeClass(s);
}
}
Now consider the following example:
public class Foo
{
public SomeClass s { get; set; }
public Foo() {}
}
You could achieve the same result as in the first example using an object initializer, assuming that you can access SomeClass, with the following code:
new Foo() { s = new SomeClass(someString) }
As you can see, an object initializer allows you to specify values for public fields and public (settable) properties at the same time construction is performed, and that's especially useful when the constructor doesn't supply any overload initializing certain fields.
Please mind, however that object initializers are just syntactic sugar and that after compilation won't really differ from a sequence of assignments.
Object initializers can be useful to initialize some small collection which can be used for testing purposes in the initial program creation stage. The code example is below:
class Program
{
static void Main(string[] args)
{
List<OrderLine> ordersLines = new List<OrderLine>()
{
new OrderLine {Platform = "AmazonUK", OrderId = "200-2255555-3000012", ItemTitle = "Test product 1"},
new OrderLine {Platform = "AmazonUK", OrderId = "200-2255555-3000013", ItemTitle = "Test product 2"},
new OrderLine {Platform = "AmazonUK", OrderId = "200-2255555-3000013", ItemTitle = "Test product 3"}
};
}
}
class OrderLine
{
public string Platform { get; set; }
public string OrderId { get; set; }
public string ItemTitle { get; set; }
}
Here is the catch. In the above code example isn’t included any constructor and it works correctly, but if some constructor with parameters will be included in the OrderLine class as example:
public OrderLine(string platform, string orderId, string itemTitle)
{
Platform = platform;
OrderId = orderId;
ItemTitle = itemTitle;
}
The compiler will show error - There is no argument given that corresponds to the required formal parameter…. It can be fixed by including in the OrderLine class explicit default constructor without parameters:
public OrderLine() {}
Object initializers are especially useful in LINQ query expressions. Query expressions make frequent use of anonymous types, which can only be initialized by using an object initializer, as shown in the code example below:`
var orderLineReceiver = new { ReceiverName = "Name Surname", ReceiverAddress = "Some address" };
More about it - Object and collection initializers
Now, years later, I am reconsidering the use of Constructors over Object Initializers. I have always liked Object initializers, as they are quick and easy. Pick which fields you want to set, and set them and you are done.
But then along came along the nullable context wherein you must specify which properties are nullable, and which are not. If you ignore using a constructor, and instead use an object initializer, the compiler is not going to be assured that your object is in fact whole (no null properties which should in fact be non-null) But a properly written and used constructor resolves all of that.
But an even better solution is to use the "required" keyword on the fields that are expected to be populated on creation, whether through a constructor, or an object Initializer. It's a new keyword of C# 11, which comes with .net 7

Categories

Resources