How to determine what object rise InvalidCastException in class assignment? - c#

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.

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.

Type and identifier are both required in a foreach statement using an object

I have the following code that was converted from vb to C#
private void LoadDropDownList()
{
DropDownList location = (DropDownList) Form.FindControl("ddlLocation_ID");
DropDownList vendorID = (DropDownList) Form.FindControl("ddlVendor_ID");
//-- Load the Sales Locations
dtDataList_v10_r1.List objList = new dtDataList_v10_r1.List();
DataSet ds = default(DataSet);
DataView dvActiveLocations = null;
ds = objList.GetSalesLocationDataset(mobjSecurity.SQLDatabase, mobjSecurity.Inst_ID);
if ((ds != null)) {
if (ds.Tables.Count > 0) {
dvActiveLocations = new DataView(ds.Tables[0]); //changed to square brackets per c# syntax 10/9/15 Max //
dvActiveLocations.RowFilter = "status='A'";
}
}
//ddlLocation_ID.DataSource = dvActiveLocations;
//ddlLocation_ID.DataTextField = "ChannelName";
//ddlLocation_ID.DataValueField = "Channel_ID";
//ddlLocation_ID.DataBind();
location.DataSource = dvActiveLocations; // changed to reference control and c# syntax 10/9/15 Max //
location.DataTextField = "ChannelName"; // changed to reference control and c# syntax 10/9/15 Max //
location.DataValueField = "Channel_ID"; // changed to reference control and c# syntax 10/9/15 Max //
location.DataBind(); // changed to reference control and c# syntax 10/9/15 Max //
//-- Load the Available Auction downloads
dtIntegration_v10_r1.Vendor objVendor = default(dtIntegration_v10_r1.Vendor);
dtIntegration_v10_r1.Vendor[] objVendors = null;
dtIntegration_v10_r1.Auctions objAuctions = new dtIntegration_v10_r1.Auctions( ref mobjSecurity); //added ref key word 10/9/15 Max //
objVendors = objAuctions.Vendors;
foreach (objVendor in objVendors)
if (objVendor.HasVendorRelationship == true)
{
//ddlVendor_ID.Items.Insert(0, objVendor.Name);
//ddlVendor_ID.Items(0).Value = objVendor.Vendor_ID;
vendorID.Items.Insert(0, objVendor.Name);
vendorID.Items[0].Value = Convert.ToString(objVendor.Vendor_ID); //changed to reference control and facilitate conversion to string 10/9/15 Max //
}
}
I get the following error when I execute it
Type and identifier are both required in a foreach statement
Now I realize that a proper statement should look like this
foreach (var somevar in object) ....
I tried this syntax and it throws this error
A local variable named 'objVendor' cannot be declared in this scope because it would give a different meaning to 'objVendor', which is already used in a parent or current scope to denote something else
So I am curious how to fix this particular error. I couldn't find it in any of the topics here so I thought I would ask
With foreach, you need to setup the type for the parameter, as so.
foreach(dtIntegration_v10_r1.Vendor objvendor in objVendors)
{
//your code.
}
You already delcared something named objVendor here:
dtIntegration_v10_r1.Vendor objVendor = default(dtIntegration_v10_r1.Vendor);
You need to pick a unique name in the loop.
The compiler error is very straightforward. You already declared a variable named objVendor which is visible inside the for loop:
dtIntegration_v10_r1.Vendor objVendor = default(dtIntegration_v10_r1.Vendor);
Now here:
foreach (var objVendor in objVendors)
if (objVendor.HasVendorRelationship == true)
which objVendor should be referenced in the second line? The one declared at the declaration of the loop or the second one? There is no way for the compiler to guess correctly, thus your code is incorrect. Fix it by giving the loop variable a different name.
foreach (var xyz in objVendors)
Now I realize that a proper statement should look like this
foreach (var somevar in object) ....
Not necessarily. You can insert the actual type name instead of var. Most of the time both will suffice.

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.

async and anonymous types

This method:
private async Task readFileInfo(string folderId)
Has a call to another method:
importCount = await VM.importVehicles(myXDoc);
Defined here: (note: I changed it from a for loop to a for each but I'm getting similar results).
public async Task<Int32> importVehicles(XDocument importXMLDocument)
{
var Importedvehicles = from vehicle in importXMLDocument.Descendants("vehicle")
select new
{
VehicleName = vehicle.Element("VehicleName").Value,
VehicleYear = vehicle.Element("VehicleYear").Value,
Odometer = vehicle.Element("Odometer").Value,
LicensePlate = vehicle.Element("LicensePlate").Value,
OilWeight = vehicle.Element("OilWeight").Value,
OilQuantity = vehicle.Element("OilQuantity").Value,
OilFilterModelNumber = vehicle.Element("OilFilterModelNumber"),
AirFilterModelNumber = vehicle.Element("AirFilterModelNumber"),
OilChangedDate = vehicle.Element("OilChangedDate"),
OilChangedOdometer = vehicle.Element("OilChangedOdometer"),
NextOilChangeDate = vehicle.Element("NextOilChangeDate"),
NextOilChangeOdometer = vehicle.Element("NextOilChangeOdometer"),
SettingDistance = vehicle.Element("SettingDistance"),
SettingMonths = vehicle.Element("SettingMonths"),
};
Int32 vehicleId;
vehicleId = await getMaxVehicleId();
try
{
foreach (var item in Importedvehicles)
{
vehicle myImportedVehicle = new vehicle();
myImportedVehicle.VehicleId = vehicleId += 1;
myImportedVehicle.ImagePath = "Assets/car2.png";
myImportedVehicle.VehicleName = item.VehicleName;
myImportedVehicle.VehicleModel = item.VehicleName;
myImportedVehicle.VehicleYear = short.Parse(item.VehicleYear);
myImportedVehicle.CurrentOdometer = Convert.ToInt32(item.Odometer);
myImportedVehicle.LicensePlate = item.LicensePlate;
myImportedVehicle.LastOilChangedDate = Convert.ToDateTime(item.OilChangedDate.Value.ToString()).ToString("d");
myImportedVehicle.LastOilChangedOdometer = (Int32)item.OilChangedOdometer;
myImportedVehicle.ReminderDistance = (Int32)item.SettingDistance;
myImportedVehicle.ReminderMonths = (Int32)item.SettingMonths;
vehicleInformation myImportVI = new vehicleInformation();
myImportVI.OilWeight = item.OilWeight;
myImportVI.OilAmount = item.OilQuantity;
myImportVI.OilFilterNumber = item.OilFilterModelNumber.Value.ToString();
myImportVI.AirFilterNumber = item.AirFilterModelNumber.Value.ToString();
myImportedVehicle.vehicleInfo = myImportVI;
m_vehicles.Add(myImportedVehicle);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message.ToString());
}
await SaveList();
return Importedvehicles.Count();
}
I'm getting an error:
Object reference not set to an instance of an object.
when I step through it the iVehicle is highlighted but then it goes directly to the for statement. Then it errors as it looks as it hasn't gotten the results from iVehicle yet.
This doesn't 100% answer your question, but it should give you a good start.
The reason the debugger jumps straight into the for...loop after the declaration of iVehicle, is because your query does not get executed when you declare it. Therefore, iVehicle at that point is not a collection of anonymous types.
When you call .Count(), the query is being executed and iVehicle is attempting to be turned into a proper collection of anonymous types. However, because something in the query (that is being executed after you call .Count()) is null, you're receiving an NullReferenceException.
You should start by verifying that both importXMLDocument and the return value from the call to Descendants() is not null.
Hope that helps anyway.
EDIT:
Now that you've given a complete example, you have heaps of places that could potentially be null.
Each time you use this:
vehicle.Element("SomeElementNameHere")
That could potentially be null. Then you're calling the .Value property on a null object.
You need to make sure each element is definitely there. Isolate each case, and determine which one is null.
Try writing your code like this:
var query =
from vehicle in importXMLDocument.Descendants("vehicle")
select new { ... };
var iVehicle = query.ToArray();
for (var i = 0; i <= iVehicle.Count(); i++)
{
...
}
You need to force the evaluation of the query. That's what the .ToArray is doing. The query itself is only the definition of the query, not the results.

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

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();
}

Categories

Resources