How can I properly use breakpoints when using an object initializer? - c#

For example, doing something like this:
foreach (DataRow row in data.Rows)
{
Person newPerson = new Person()
{
Id = row.Field<int>("Id"),
Name = row.Field<string>("Name"),
LastName = row.Field<string>("LastName"),
DateOfBirth = row.Field<DateTime>("DateOfBirth")
};
people.Add(newPerson);
}
Setting a breakpoint to an individual assignation is not possible, the breakpoint is set to the entire block.
If I want to see specifically where my code is breaking, I have to use:
foreach (DataRow row in data.Rows)
{
Person newPerson = new Person();
newPerson.Id = row.Field<int>("Id");
newPerson.Name = row.Field<string>("Name");
newPerson.LastName = row.Field<string>("LastName");
newPerson.DateOfBirth = row.Field<DateTime>("DateOfBirth");
people.Add(newPerson);
}
Or maybe I'm missing something. Can you properly debug when using an object initializer?

Object initializers are just syntactic sugar and get translated when they're compiled. Your original object initializer becomes something like this:
var temp = new Person();
temp.Id = row.Field<int>("Id");
temp.Name = row.Field<string>("Name");
temp.LastName = row.Field<string>("LastName");
temp.DateOfBirth = row.Field<DateTime>("DateOfBirth");
var person = temp;
Since the whole block is translated like that you can't break inside one step. If you absolutely need to break on one particular step, you have a few options.
Break it up. Don't use object initializers while debugging, and you can put them back afterwords.
Temp variables. Instead of assigning Id = row.Field<int>("Id") directly, assign row.Field<int>("Id") to a temp variable first (or whichever one you want to debug) and then assign the temp variable to the object initializer property.
Method call. You can wrap some of the code in a custom method call solely to allow you to add a breakpoint within your custom method. You could even generalize it like this:
Id = BreakThenDoSomething(() => row.Field<int>("Id"));
public static T BreakThenDoSomething<T>(Func<T> f)
{
Debugger.Break();
return f();
}

Related

Object name reference not going out of scope

I've spotted a very confusing behavior:
I have two for blocks. I declare two distinct objects with the same name newDevice inside each one. I expect that the first object goes out of scope when the first for block ends, and a for a new object to be created in the second for block.
What actually happens is that the initial value is never "released" from the variable name. The variable name still references the first object.
The compiler doesn't complain about already declared object, and if I don't use the var keyword in the second attribution, a "cannot resolve symbol" error arises.
Here's the simplified code:
/* First "for" loop */
var masters = networkDiscoveryCompletedEventArgs.ConnectionInfos.Where(x => x.DataModelHandshake.DeviceId == masterId).ToList();
foreach (var connectionInfoMaster in masters)
{
// First declaration. newDevice's type, after construction, is "MasterDevice".
var newDevice = new MasterDevice
{
DeviceName = connectionInfoMaster.DataModelHandshake.Name,
DeviceId = connectionInfoMaster.DataModelHandshake.DeviceId,
ConnectionInfo = connectionInfoMaster
};
MasterDevices.Add(newDevice);
}
/* Second "for" loop */
var slaves = networkDiscoveryCompletedEventArgs.ConnectionInfos.Where(x => x.DataModelHandshake.DeviceId != masterId).ToList();
foreach (var connectionInfoSlave in slaves)
{
// Second declaration. Inspecting newDevice in debbug mode,
// it's not undeclared at this point. Instead, it retains
// the previous object reference ("MasterDevice"). newDevice's type, after construction,
// is also "MasterDevice".
var newDevice = new SlaveDevice
{
DeviceName = connectionInfoSlave.DataModelHandshake.Name,
DeviceId = connectionInfoSlave.DataModelHandshake.DeviceId,
ConnectionInfo = connectionInfoSlave
};
SlaveDevices.Add(newDevice);
}
Using different names solves the issue.
Am I missing something, or is it a compiler bug?
This never happened before, and I'm really confused.

How to determine what object rise InvalidCastException in class assignment?

I have a class assignment like that:
Variable currentVar = new Variable() {
Id = var.Field<int>("id"),
Address = var.Field<string>("address"),
Matricola = var.Field<int>("matricola"),
MachModel = var.Field<string>("modello"),
MachType = var.Field<string>("machinetype"),
Part = var.Field<string>("part"),
PartNumber = var.Field<int>("partnumber"),
PartMeasurement = var.Field<string>("partmeasurement"),
Priority = var.Field<int>("priority") ,
EnableEventHub = var.Field<bool>("enableeventhub"),
MinAgeEventHub = var.Field<int>("minageeventhub")};
Sometime it rise an InvalidCastException. When I debug the application I cannot see what "var" values are because they're in another context, and the line reference on the stack report the first because it is only one statement.
What is a good way to determine what field of "var" gives me the exception?
My block is in a normal try catch and I log the exception message and stack.
You could try to assign all data before you declare the class.
Like that:
int iMatricola = var.Field<int>("matricola");
string strAddress = var.Field<string>("address");
Variable currentVar = new Variable() {
Address = strAddress,
Matricola = iMatricola
};
I prefer this way if I have to use not type-safe values.

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

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.

How can I break inside an C# automatic constructor block?

I was wondering if there are any way to put break point inside an automatic constructor/object initializer block?
Example:
var x = new Person()
{
Name = 'John',
Age = DateTime.Now - Birthdate
}
I want to put breakpoint on the 4th line. This is very helpful when setting like 150 fields with different logic for each property and the type you are creating an instance of is not under your control (e.g. EF4 entity), therefore you cannot create a custom constructor. Any ideas?
A workaround you can use for this issue is writing the code like this to ease your debugging:
var x = new Person();
x.Name = "John";
x.Age = DateTime.Now - Birthdate;
Wrap the value on a line where you want a breakpoint in a self calling function:
var x = new Person() {
Name = new Func<string>(() =>"John").Invoke(),
Age = DateTime.Now - Birthdate
};
Now you will be able to "step into" it. It won't be of much use, though, as x will remain null until the end of the block.
If Name property is not automatic you can put a breakpoint inside set of that property.
If your doing it that way then you can't. You can out a breakpoint on the entire block and step through it using F11.
Why dont you do the following
Person p = new Person();
p.Name = "John";
p.//Blah

To add an item to list do I need to create a new object?

I am adding an object to a list and then afterwards setting the object variable to null. To add the another object to the list do i need to create a new object. The code I am using is below:
UpdateData = new MismatchData();
UpdateData.CINID = currentInLoopCIN_ID;
UpdateData.ColumnMapID = <some integer>;
UpdateData.WMSValue = <some integer>;
lsMismatchData.Add(UpdateData);
UpdateData = null;
Do I need to have the first line?
UpdateData = new MismatchData(); //Do I need to have this line of code?
Since you're setting UpdateDate to null, you'd get an error when you'd try to set UpdateData.CINID, the second time around (you'd be accessing a null object).
Your null assignment is the redundant line of code here. Since you're always assigning a new UpdateData to your variable, you don't need to reset it in between.
With or without the null assignment, you'll still need to create a new instance every time, though, otherwise you'd just be updating the old instance.
If you want to cut down on lines of code, you could do something like this:
lsMismatchData.Add(new UpdateData {
CINID = currentInLoopCIN_ID,
ColumnMapID = <some new integer>,
WMSValue = <some new integer>
});
Or, since it looks like you're in a loop, you might be able to do something like this, to make your code even terser:
var lsMismatchData = yourLoopSource.Select(x => new UpdateData {
CINID = x.CIN_ID, // apply your own logic to getting the proper values here.
ColumnMapID = x.XYZ,
WMSValue = x.ABC
}).ToList();
Yes, of course. Otherwise UpdateData will be null and you can not access UpdateData.CINID.
But (using C# 3.0+) you can use the following syntax to make it shorter:
lsMismatchData.Add(new MismatchData() { CINID = currentInLoopCIN_ID, ColumnMapID = <x> });
Yes, you'll have to instantiate a new object to the variable UpdateData as
UpdateData = new MismatchData();
before you can start filling its properties again and also before you add it again to lsMismatchData, otherwise you'll get a null reference exception
Of course, otherwise your reference is null. Then when you try to set the fields before adding the new entry you will get a NullReferenceException.
If instead you don't set it to null and modify the old object, you will modify all the other entries in the list, since they point to the same object.

Categories

Resources