Why the C# property initializer (new()) is written as that? - c#

Info myPath = new Info()
{
path = oFile.FileName
};
...
class Info
{
public string path;
public string Path
{
get { return path; }
set { path = value; }
}
}
Above is the C# code from some program and it can work normally. But I don't understand it well. The first question is that why path = oFile.FileName is not written as path = oFile.FileName; ? Why the semicolon can be removed?
The second question is that why I cannot write it like this: myPath.path = oFile.FileName ? There will give error message by Visual Studio 2012.

That construct is an object initializer. It's not a list of arbitrary statements - it's only initialization of fields and properties, and they're comma-separated:
Foo x = new Foo // Implicitly calls the parameterless constructor
{
Property1 = value1,
Property2 = value2
};
That's shorthand for:
Foo tmp = new Foo();
tmp.Property1 = value1;
tmp.Property2 = value2;
Foo x = tmp;
Object initializers were introduced in C# 3, along with collection initializers which are effectively syntactic sugar for repeated calls to Add. So:
List<string> names = new List<string>
{
"Foo", "Bar"
};
is equivalent to:
List<string> tmp = new List<string>();
tmp.Add("Foo");
tmp.Add("Bar");
List<string> names = tmp;

You have many ways of initializing an object in C#.
Here you can do what you have written, which will be an equivalent to this:
Info myPath = new Info();
myPath.Path = oFile.FileName;
this syntax
Info myPath = new Info()
{
path = oFile.FileName
};
is just a shortcut, and can be more readable, but will do the same thing. Actually it seems that it was kind of taken from VisualBasic (the With statement).
To explain the above syntax:
YourClassName <your_variable> = new YourClassName()
{
<property_name> = value,
<anotherProperty> = value,
...
<last_property> = value
};
the last way is to have a constructor that takes the path as an argument and initializes it. This is actually the way where there is the less operations done by the cpu (but it's not significant).

In C# 3.0, they added a new & helpful feature for initializing objects as a single statement/expression.
Whereas before, you'd have to issue separate statements:
Info myPath = new Info();
myPath.Filename = ...
myPath.AnotherProperty = ...
myPath.AnotherAnotherProperty = ...
You can now perform the same assignments in one step:
Info myPath = new Info
{
Filename = ...
AnotherProperty = ...
AnotherAnotherProperty = ...
};
This is especially useful, for constructing objects in Linq queries (without having to custom-code object constructors).
For example:
someList.Select(x => new SomethingElse{ SomeProperty = x.Something });

Info myPath = new Info()
{
path = oFile.FileName
};
means:
Initialize a new Info Class and add to property path the value oFile.FileName
it is the short version of:
Info myPath = new Info();
myPath.path = oFile.FileName;
you do not need ';' because you can stack more properties in the brackets like this:
Person p = new Person()
{
Name = "John",
Age = 25
};

C# allows you to initialize properties of an object at the same time that you're constructing it.
These are all equivalent:
var foo = new Foo();
foo.Property = "Bar";
foo.AnotherProperty = 12;
var foo = new Foo()
{
Property = "Bar",
AnotherProperty = 12
};
// The parentheses are not really necessary for parameterless constructors
var foo = new Foo
{
Property = "Bar",
AnotherProperty = 12
};

It is the new way of initializing variables in C#. You can also skip '()' signs.
You can initialize like that also lists, arrays, etc. in brackets you must insert elements which you want to initialize in your object.

Info myPath = new Info()
{
path = oFile.FileName
};
is equivalent to
Info myPath = new Info();
myPath.path = oFile.FileName;
When initializing with the object initializing structure, you create a list of property assignments as you noted. This way you can create objects and assign variables in one call without having an explicit constructor. The above could easily have been written in one line.
More info can be found on the MSDN website.

Related

Forgotten "new" declaration in collection initialization: what does this code do, and why does it compile?

When initializing objects, I often write code like this:
var myObj = new MyObject
{
Number = 1,
ListOfStuff = new List<Stuff>
{
new Stuff()
}
}
However, sometimes I forget the new List<Stuff>, and instead write:
var myObj = new MyObject
{
Number = 1,
ListOfStuff =
{
new Stuff()
}
}
I wouldn't expect this to compile, but it does. ListOfStuff isn't initialized as I would expect, however -- it's empty. What exactly does this code actually do?
Both object initialization syntax and collection initialization syntax are just syntactic sugar transformed by compiler at compile time insto assignments and method calls:
object initialization syntax is transformed into property assignments,
collection initialization syntax is transformed into proper Add method calls
So your code is equivalent to:
var myObj = new MyObject();
myObj.Number = 1;
myObj.ListOfStuff.Add(new Stuff());
It's a valid C# code and it will work if default constructor on MyObject initializes ListOfStuff property. It will throw NullReferenceException if it doesn't.
The first version of your code explicitly assigns new List() to ListOfStuff before calling Add:
var myObj = new MyObject();
myObj.Number = 1;
myObj.ListOfStuff = new List<Stuff>();
myObj.ListOfStuff.Add(new Stuff());
It's interesting also that the following way of initializing ListOfStuff will generate a compile error:
var myObj = new MyObject();
myObj.Number = 1;
myObj.ListOfStuff =
{
new Stuff()
};
};

Issue related to make a copy of List variable in C#

I have function that accepts a Parameters of type List as follows:
private decimal CalculateIRR(List<AmortizationDepotResult> lstAmortizationDepotResult, decimal carryAmount)
{
if (lstAmortizationDepotResult.Count > 0)
{
var lstLoanDepots = lstAmortizationDepotResult.ToList();
lstLoanDepots.First().Payment = carryAmount;
In above code, i just want to change the parameter value(Payment) of first object in the list. if i execute above code, carryAmount value gets reflect in lstAmortizationDepotResult as wel as in lstLoanDepots also.
but i dont want to change value in lstAmortizationDepotResult, it should reflect only in lstLoanDepots.
so how do i solve my problem ???
Thanks..
Welcome to the world of objects, where your variables are not values but references. Thus:
var a = new Foo();
var b = a;
a.Bar = "Hello!";
Console.WriteLine(b.Bar); // output = "Hello!"
If you want to copy an object's values to another identical object in such a way that they do not share the same memory space, you'll have to do that explicitly:
var b = new Foo
{
Bar = a.Bar,
OtherField = a.OtherField
};
Enumerable.ToList creates a new list but all objects contained reference the original objects. If you want a deep copy of all objects in the list provide an appropriate constructor or intialize all properties manually.
if (lstAmortizationDepotResult.Count > 0)
{
var lstLoanDepots = lstAmortizationDepotResult
.Select(x=> new AmortizationDepotResult{
Payment = carryAmount,
Property2 = x.Property2, Property3 = x.Property3, ....
})
.ToList();
// ...
I'd implement IClonable interface in your AmortizationDepotResult class:
public class AmortizationDepotResult ...
IClonable {
...
Object IClonable.Clone() {
return Clone();
}
public AmortizationDepotResult Clone() {
AmortizationDepotResult result = new AmortizationDepotResult();
...
result.Payment = Payment;
...
return result;
}
}
So in order to have a deep copy you can do
private decimal CalculateIRR(List<AmortizationDepotResult> lstAmortizationDepotResult, decimal carryAmount) {
if (lstAmortizationDepotResult.Count > 0) {
var lstLoanDepots = lstAmortizationDepotResult
.Select(item => item.Clone())
.ToList();
lstLoanDepots[0].Payment = carryAmount;
...
}

Can I use object initializer outside construction of an object?

Given object initializers:
Foo foo = new Foo{ Name = "Jhon", Value = 2, IsMale = true };
Can they be somehow used elsewhere?(outside object construction) So that insted of using:
foo.Name = "Name";
foo.Value = 5;
...
foo.DoSth();
To just use something like:
Name = "Name";
Value = 5;
...
DoSth();
Given that this is outside the class hierarchy of foo. That is to avoid places where you use one object's members many many times.
For example in VB/GML(GameMaker's scripting language) one can use:
with(foo)
{
Name = "Name";
Value = 5;
...
DoSth();
}
Instead of foo.something
So is there something like this in C#?
No, object initializer is the only place where assignment syntax like that can be used. If you need to assign multiple fields at once from many different places in code without duplication, you could define a method that encapsulates all the assignments for you:
void SetNameAndGender(string f, string l, bool isMale) {
FirstName = f;
LastName = l;
IsMale = isMale;
}
Unfortunately, it does not let you set an arbitrary group of properties, like the VB syntax that you show.

add properties to an object of type object

object o = new { foo = 1 };
Is there any other way to add properties to the object?
Neither o["foo"] = 1 nor o.foo = 1 seems to be working.
And if i type
var o = new { foo = 1 };
Why is the type of var an "AnonomuysType" and not object?
You can't just add properties to compiled types. The only time that will work as properties (well, kind-of) is if you are using the dynamic API, and the object is something that supports dynamic properties, for example:
dynamic obj = new ExpandoObject();
obj.Foo = 123;
obj.Bar = "abc";
however, those values are not available via reflection. An easier approach may be something that behaves as a dictionary:
var obj = new Dictionary<string,object>();
obj["Foo"] = 123;
obj["Bar"] = "abc";
there are more discoverable, via the dictionary API. Re your final question: when you do:
var o = new { foo = 1 };
the new { foo = 1 } causes the compiler to generate an anonymous type, which is a regular C# class with read-only properties and an unpronounceable name. This can be referred to as object (it is a regular class, after all), but when you use var the compiler uses the known type (with the horrible name), which gives you access to the properties (.foo in this case).
All objects inherit from Object even an anonymous type(see this question). You can see that here:
object o = new { foo = 1 };
if (o is object)
Console.Write("Yes, i'm an object!");
else
Console.Write("no, no, i'm not an object!");
You cannot add properties to an anonymous type, only when you you create it.
You could use a Dictionary<string, object> instead:
var o = new Dictionary<string, object>();
o.Add("Foo", 123);
o.Add("Bar", "abc");
Now you can access them in this way:
object bar = o["Bar"]; // "abc"

Create generic array in VB.NET

I want to reach the same result as I obtain in C# with this syntax, but in VB.NET:
// This is my generic object (coming from Json parsing!):
var genericContent = new { Name = "name1", Value = 0 };
// I would like to have a generic list, created by this generic item:
var myList = (new[] { genericContent }).ToList();
// So, I can add any other generic items (with the same structure)...
myList.Add(new { Name = "name2", Value = 1 });
// And treat them as a normal list, without declaring the class!
return myList.Count;
...so, I just want to create a generic array in VB.
In C# it works well, but I don't kwon this VB.NET syntax...
I'm using .NET framework 3.5!
Thank you!
No problem here:
Dim genericContent = new with { .Name = "name1", .Value = 0 }
Dim myList = {genericContent}.ToList()
myList.Add(new with { .Name = "name2", .Value = 1 })
At least in .Net 4.0 (VB.Net 10.0).
For earlier versions: No, not possible without a helper method.
I think with that framework there's no compact syntax for that, as in C#...
Try using this way...
Declare a method like this (shared is better I think):
Public Shared Function GetArray(Of T)(ByVal ParamArray values() As T) As T()
Return values
End Function
So you can create an array passing a generic parameter, than with LINQ should be easy to create a generic list:
Dim genericContent = New With { Name = "name1", Value = 0 }
Dim myList = (GetArray(genericContent)).ToList()
myList.Add(New With { Name = "name2", Value = 1 })
return myList.Count

Categories

Resources