I have a strange issue with the object initializer syntax.
Here are my sample classes:
public class Foo
{
public Bah BahProp { get; set; }
}
public class Bah
{
public int Id { get; set; }
}
Consider following three ways to initialize an object:
The old, verbose but explicit way, working correctly:
var foo1 = new Foo();
foo1.BahProp = new Bah();
foo1.BahProp.Id = 1;
// correctly initialized
The second way i'm always using, using object initializer syntax:
var foo2 = new Foo
{
BahProp = new Bah { Id = 1 }
}; // correctly initialized
A third way resharper has suggested my collegue with a different resharper version(is it a bug?):
var foo3 = new Foo
{
BahProp = { Id = 1 }
}; // NullReferenceException
What is the last approach doing differently?
My resharper version is 2016.1.1, my colleague was on 10.02. My resharper suggested the second way. But what does the third way do and when is it useful?
Update: So it seems that it was a bad resharper sugestion to use the last way, that's why they have changed it meanwhile to use the second way.
You can avoid the NullReferenceException if you want to use the third way by initializing all properties/fields that are reference types inline or in the constructor.
I will definitely not use this strange property assignment syntax.
new Foo { BahProp = { Id = 1 } }
compiles to:
new Foo().BahProp.Id = 1;
or, little more verbose:
var foo3 = new Foo();
foo3.BahProp.Id = 1;
So BahProp is null. You're not constructing it.
(This is perhaps the most confusing syntax in all of C#)
Option 2 works because you're calling the constructor of Bah.
Option 3 would also work if you initialize BahProp inside the constructor of Foo. It will have been constructed by the time BahProp = { Id = 1 } is called.
The same is seen with collection initializers:
public class Foo {
public List<int> Numbers { get; set; }
}
var foo = new Foo { Numbers = { 1, 2, 3 } };
This does not initialize the List. It only calls Add on it.
You really must see new MyObject() { X = 1, Y = 2 } as two distinct parts:
new MyObject() constructs a new object and
{ X = 1, Y = 2 } sets the values of its properties (and that's all it does).
Object and collection initializers can be nested. The top-level initializer must follow a constructor, but a nested initializer does not.
Related
I am using an object initializer for a st object:
public class Container
{
public Container () { ContainedItem = new Item; }
public Item ContainedItem { get; set; }
}
public class Item
{
public string Value { get; set; }
}
var MyContainer = new Container()
{
// I want to populate the the property Value of the property Item
// with the second line rather than the first
ContainedItem = new Item() { Value = FooString }, // This works
ContainedItem.Value = FooString // This assigns to the same member but does not work
};
The second initializer line gives the error:
The name 'ContainedItem' does not exist in the current context.
Invalid initializer member declarator.
and suggests declaring ContainedItem somewhere in local scope.
Now as the first line works it can be seen that ContainedItem is in fact a valid property of Container and that MyContainer.ContainedItem is definitely not null... so why does the following line fail to recognise it?
The syntax for inline object initialisation is well specified. You can't just make stuff up and expect the compiler to understand. The syntax is strictly:
{
Property1 = Value1,
Property2 = Value2,
...
}
c.x is not a property of st. c is. Hence, you cannot say c.x = Bar[i].x
From the C# Language Specification section 7.6.10.2:
object-initializer:
{ member-initializer-listopt }
{ member-initializer-list , }
member-initializer-list:
member-initializer
member-initializer-list , member-initializer
member-initializer:
identifier = initializer-value
initializer-value:
expression
object-or-collection-initializer
You can assign values to "sub-properties" as it were, just not with that syntax. Here's a complete example:
using System;
public class Container
{
public Item Item { get; set; } = new Item();
}
public class Item
{
public string Value { get; set; }
}
class Test
{
static void Main(string[] args)
{
var container = new Container
{
Item = { Value = "hello" }
};
}
}
The object initializer in Main is equivalent to:
var tmp = new Container();
tmp.Item.Value = "hello";
var container = tmp;
Note that this relies on Container.Item returning a valid object without it having been explicitly initialized in the object initializer - which is the case in my example, but isn't always the case.
You can´t use an expression like c.x on the left side of an assignement within an initializer. This includes methods-calls as well as getters/setters:
var s = new S { x.MyMethod() };
The only thing you can do in an intializer is to set a property of the current type.
From MSDN:
Object initializers let you assign values to any accessible fields or
properties of an object
However c.x is not a field or property of st, it´s not even a valid name.
That´ll work however:
var s = new st();
{
c = new ct()
};
s.c.x = Bar[i].x;
That's cause you are trying to do inside object initializer which is for initializing the object members and c.x isn't a defined member of object s. Thus the said error. Rather try doing it outside of object initializer saying
s.c.x = Bar[i].x;
I was recently working on some code, that has changed from using decimal to use a complex type that has the decimal number and a type to represent a fraction. I had to update some tests, and while typing I forgot to add the new keyword. The code compiled but the test kept failing, throwing a NullReferenceException. There I realized the missing new and that the property was not initialized. Has anybody an idea why this happening? I could not find anything in the C# lang specification that would explain this.
Here is the code sample:
public class Fraction
{
public int Numerator { get; set; }
public int Denominator { get; set; }
}
public class MyDecimal
{
public decimal? Decimal { get; set; }
public Fraction Fractional { get; set; }
}
public class ClassA
{
public MyDecimal Value { get; set; }
}
//...
var instance = new ClassA
{
Value = // new MyDecimal is missing here
{
Decimal = 2.0m,
Fractional = new Fraction
{
Numerator = 3,
Denominator = 4
}
}
}
Please note that I'm using C# 6 and VS 2015, but I get the same result also in LINQPad.
If somebody could explain this (I'm looking in your direction Jon Skeet :) ) I would be glad.
The C# Specification 5.0 defines object initializer as (7.6.10.2 Object initializers):
An object initializer specifies values for zero or more fields or properties of an object.
object-initializer:
{ member-initializer-listopt }
{ member-initializer-list , }
And after the detailed explanation there is an example given which is very similar to your code:
If Rectangle’s constructor allocates the two embedded Point instances
public class Rectangle
{
Point p1 = new Point();
Point p2 = new Point();
public Point P1 { get { return p1; } }
public Point P2 { get { return p2; } }
}
the following construct can be used to initialize the embedded Point
instances instead of assigning new instances:
Rectangle r = new Rectangle {
P1 = { X = 0, Y = 1 },
P2 = { X = 2, Y = 3 }
};
which has the same effect as
Rectangle __r = new Rectangle();
__r.P1.X = 0;
__r.P1.Y = 1;
__r.P2.X = 2;
__r.P2.Y = 3;
Rectangle r = __r;
But there is only one difference, the Point instances here are initialized inside of the Rectangle class which occurs in the constructor of Rectangle.
So the syntax is valid by the specification, but you need to make sure Value is initialized before using the object initializer to initialize its properties in order to avoid NRE.
An object-initializer doesn not really instantiate your members.
See the following code:
var myInstance = new MyInstance { MyMember = new MyMember { Value = 3 }; }
This compiles to:
var myMember= new MyMember();
myMember.Value = 3;
var myInstance = new MyInstance();
myInstance.MyMember = myMember;
In your case you forgot to instantiate MyMember, thus the object-intializer tries to access that property and assign further values to it. This is due to the fact that object-initializers allways run after the appropriate constructor, which wasn´t called in your case. So in your case it compiles to this:
var myInstance = new MyInstance();
myMymber.Value = 3;
Causing a NullReferenceException as myMember was never instantiated.
Why does this even compile? Well, I assume the compiler assumes that you instantiate MyMember within the constructor of MyInstance. It can´t know wheather you actually did this.
class Instance
{
MyMember MyMember = new MyMember();
}
Leaving members null is of course absoluetely valid.
The object initializer syntax allows you to initialize an object without creating it first. This is rather important if you want to preserve object identity.
For example, you could make ClassA.Value a read-only property, and initialize it in the object constructor:
public class ClassA
{
public ClassA()
{
Value = new MyDecimal();
}
public MyDecimal Value { get; private set; }
}
This behaviour is of course explicitly outlined in the C# specification (excerpt from version 5):
7.6.10.2 Object initializers
A member initializer that specifies an expression after the equals sign is processed in the same way as an assignment (§7.17.1) to the field or property.
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.
Since your Value initializer is a nested initializer, it allows you to just assign members of Value without initializing it - as long as Value has been initialized already, of course. The compiler has no way of verifying whether Value is null, so it cannot give you an error.
I learned about following syntax today
protected String TaskTitle { get; set; }
If I am correct this essentially translates to something like:
String _taskTitle;
protected String TaskTitle {
get { return _taskTitlel }
set { _taskTitle = value; }
}
My question is how can we use it now with objects to set and get certain values? Lets assume object is named MyTest(String title) how would I set TaskTitle equal to a passed in argument title? and afterwards instead of having methods like .getTitle(..) .setTitle(..) how would I take advantage of this {get; set;} syntax?
I understand that this might be getting long, but I believe this "sub question" belongs here, can I use this for arrays? Lets assume I have other object named MyTestTwo(String title, String description, int number); That inherits from first one, and I'd like to have an array MyTestTwo[] { get; set; } as part of MyTest() object, how could I populate it?
I know this might be a lot to ask, but I want to understand this {get; set;} syntax as I am new to it and new to c# in general, so far documentation is a bit confusing to me.
You should mark your property public to 'see' it in classes that do not derive your current class.
You can set it like this then:
yourInstance.TaskTitle = "test 123";
As an answer on your second question:
You can populate the array like you normally would when using variables:
yourInstance.ArrayProperty = new string[1];
yourInstance.ArrayProperty[0] = "test 123";
You can use the { get; set; } syntax like this to modify properties on existing objects:
myTest.TaskTitle = "A brand new title";
And like this to read data from existing objects
string currentTitle = mytest.TaskTitle;
Additionally you can use the following shorthand syntax to initialize a new object:
MyTest myTest = new MyTest{ TaskTitle = "a new task"};
There's some other shorthand syntax you can use for initializing ICollection data structures, which is explained quite well here: http://msdn.microsoft.com/en-us/library/bb384062.aspx
in C# you use the properties by either getting the value via a string a = class.TaskTitle; or setting via class.TaskTitle = "foo";
As far as array objects, try this:
Foo foo = new Foo();
foo.bar = new Bar[5];
foo.bar[0] = new Bar();
foo.bar[1] = new Bar();
...
After which you can access the properties of the Bar via the same syntax as any other object:
foo.bar.SomeMethod();
Or, sans nested classes:
Foo[] foo = new Foo[2];
foo[0] = new Foo();
foo[1] = new Foo();
i am assuming this is your constructor
MyTest(String title)
{
TaskTitle=title;
}
Modifier returntype PropertyName
{
get;
set;
}
get and set are methods ....in c# we use them becouse they are compact and simple.
or you can use methods get and set by creating in your class separately...like
public returntype get()
{
return yourPrivateMember;//
}
public returntype set(type value)
{
yourPrivateMember=value;//in certain cases you dont want the user the mess your private variable and you can control how the user interacts with your private variables
}
Take this code for example:
class Jooky
{
static long Last;
public Jooky() { Id += Last++; }
public long Id { get; set; }
public string Name { get; set; }
}
class Flooky
{
public Flooky() { Jooky1 = new Jooky(); Jooky2 = new Jooky(); }
public Jooky Jooky1 { get; set; }
public Jooky Jooky2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<Flooky> Flookies = new List<Flooky>();
//I build a collection of flookies to emulate the service call of
//FlookyProxy.GetAllFlookies().
for (int i = 0; i < 5; i++) Flookies.Add(new Flooky());
//This makes a collection of all the jookies in all the flookies.
var Jookies = Flookies.Select(f => f.Jooky1).Union(Flookies.Select(f => f.Jooky2));
//I get the jooky.
Jooky Jooky = Jookies.Single(j => j.Id == 2);
//Fig 1: I just got a jooky out of the collection. One of the flookies
//has a reference to this jooky. I want to set the jooky to a new
//reference, but still want the same flooky to reference it.
Jooky = new Jooky { Name = "Bob" };
//I get the jooky again
Jooky = Jookies.Single(j => j.Id == 2);
//However, this writes an empty string because only the Jooky variable
//I previously declared was affected.
Console.WriteLine(Jookies.Single(j => j.Id == 2).Name);
//Basically, I want the code in Fig 1 above to be the same as:
//Flooy.Jooky = new Jooky { Name = "Bob" };
Console.Read();
}
}
Basically, variable A is referencing Aa in memory and variable B is referencing object Bb in memory. I want to make A reference the same object in memory as B without going like A = B;. Instead, I want to replace the physical object in memory with another, ultimately going like Aa = Bb;.
Is this at all possible?
Update: Primary rule: I cannot reference the flooky directly, so I can't be all like Flooky.Jooky1 = new Jooky() or Flookies[3].Jooky1 = new Jooky().
Maybe this is possible with unsafe code as suggested by havardhu, but it's definitely not possible with safe code. It's important to understand why doing what you're trying to do is unsafe. Not only does it break encapsulation, it breaks type safety. Consider this example.
class Me : IHaveCar
{
BuickCentury myCentury = new BuickCentury(2004);
public Car Car { get { return myCentury; } }
public void Drive()
{
myCentury.CruiseWithAuthority();
}
}
class EvilOilChangeService
{
public void ChangeOil(IHaveCar customer)
{
Car car = customer.Car;
// here's the fictional "replace object in memory" operator
car <<== new VolkswagenBeetle(2003);
}
}
The EvilOilChangeService can create a situation where myCentury is referencing a VolkswagenBeetle! I'm going to be in trouble when I try to go for a Drive because a VolkswagenBeetle just can't CruiseWithAuthority like a BuickCentury can (especially when the driver is 6'2")
Even in C/C++ which allows willy-nilly memory access, I would still be quite surprised by code that does what you want to do. This is why most of the other answers are suggesting a different approach or design.
Change:
//Jooky = new Jooky { Name = "Bob" };
Jooky.Name = "Bob" ;
The resullt of the .Single() is a reference to an instance (object). You were just overwriting the reference with one to a new object. The old object was not changed or overwritten.
To understand what's going on, and to adjust what you are aiming for, look up "Value Type and Reference Type". Lots of reading to do.
After reading the comment:
If your Details (Jookies) are going to change independently of their Owners (the Flookies) then you just need another layer of indirection.
A simple suggestion:
do not store references to the details (since they will change)
store a DetailId instead (JookyId1, JookyId2)
keep the Details in a Dictionary (Dictionary<int,Jooky>)
create a (readonly) property in Owner to get Detail1 by looking it up in the dictionary.
You can write unsafe code in C# which enables you to operate on direct memory.
Have a look here for details:
Pointers and arrays in C#
You'll notice that you can use the familiar pointers (*) and addresses (&) from C and C++.
Here's an example of an unsafe swap, which I think is what you're after:
Unsafe swap in C#
Jooky = new Jooky { Name = "Bob" };
Flookies[0].Jooky1=Jooky;
If you want to replace and object with another without just assigning references you just to copy all the data fields to the other object. Not sure if i have understood your question correctly.
When you're working with references, every assignment to a reference changes the object that reference points to.
So, when you say:
Jooky Jooky = Jookies.Single(j => j.Id == 2);
you're creating a reference to the Jookie with Id == 2. And then, when you say Jooky = new Jooky { Name = "Bob" };, you're telling that reference you created to point to the Jooky you have just created instead.
So, if you want to set a new value to the Jookie1 property (wich is a placeholder for a reference to a Jookie object) of the Flookies[0] object, you got to say:
Flookies[0].Jooky1 = new Jooky { Name = "Bob" }; (as stated by #Ashley John's answer).
That way, you're telling the Flookies[0].Jooky1 reference to point to the new Jooky { Name = "Bob" }; object.
For further explanation, see http://msdn.microsoft.com/en-us/library/ms173104.aspx .
If you have access to the Jookie class, you could add a property that holds the parent Flookie of the Jookie:
class Jooky
{
static long Last;
public Jooky(Flooky parent)
{
Id += Last++;
Parent = parent;
}
public long Id { get; set; }
public string Name { get; set; }
public Flooky Parent { get; private set; }
}
and then access the parent Flookie and change it's Jookie1 property:
Flookie flookie = Jookies.Single(j => j.Id == 2).Parent;
flookie.Jookie1 = new Jookie { Name = "Bob" }
I'm trying to go the opposite way of what you would normally do.
I have two POCO classes A and B where B inherrits from A
public class A
{
public int Foo { get; set; }
}
public class B : A
{
public int Bar { get; set; }
}
B is ment as an extention to A with additional information.
I start by having an instance of class A
A a = new A { Foo = 1 };
And then I wish to extend the information in class A with the additional information and get the final class B. I could map every property from class A to the property in class B, but it does not make much sence to me:
A a = new A { Foo = 1 };
B b = new B { Foo = a.Foo, Bar = 2 };
Or in constructor
A a = new A { Foo = 1 };
B b = new B(a) { Bar = 2 }; // Mapping of value Foo is done in constructor of object B
The result is in eather case a manual mapping of values from object A to B.
There must be a smarter way to do this... any suggestions?
If you are actually changing type (rather than casting) - then if you have only a few classes, then just write conversion code - perhaps a ctor for B that accepts a template A. If you have a lot of classes... there are tricks you can do with either dynamic code or serialization. PropertyCopy in MiscUtil will do this, for example (using a dynamic Expression to do the work very quickly):
A a = new A { Foo = 1 };
B b = PropertyCopy<B>.CopyFrom(a);
b.Bar = 2;
I would regard the "smart" way as being your last suggestion - write a copy constructor for B that knows how to instantiate itself from an A.