Exception when adding item to list<t> - c#

I always get a "An unhandled exception of type 'System.NullReferenceException' occurred in myapp.exe" when code reaches _match.Players2.Add(_hero);
I am not sure why, I initialized _match as well as _hero, when I debug I see that there are no null values. I am not sure why I am getting this exception, am I missing something?
Here is my code:
public static List<MyDotaClass.MatchHistory> GetMatchHistory(string uri)
{
var HeroCollection = new List<MyDotaClass.DotaHero>();
var MatchCollection = new List<MyDotaClass.MatchHistory>();
string response = GetDotaWebResponse(uri);
dotadata.Dota.MatchHistoryRootObject matches = JsonConvert.DeserializeObject<dotadata.Dota.MatchHistoryRootObject>(response);
foreach (var match in matches.result.matches)
{
var _match = new MyDotaClass.MatchHistory();
_match.MatchID = match.match_id.ToString();
foreach (var player in match.players)
{
var _hero = new MyDotaClass.DotaHero();
foreach(var h in heros)
{
if(player.hero_id.ToString().Equals(h.HeroID))
{
_hero.HeroName = h.HeroName;
_hero.HeroNonCleanName = h.HeroNonCleanName;
_hero.HeroID = h.HeroID;
_match.Players2.Add(_hero);
}
}
}
MatchCollection.Add(_match);
}
return MatchCollection;
}
public class MyDotaClass
{
public class DotaHero
{
public string HeroName { get; set; }
public string HeroNonCleanName { get; set; }
public string HeroID { get; set; }
}
public class MatchHistory
{
public string MatchID { get; set; }
//public List<DotaHero> Players { get; set; }
public List<MyDotaClass.DotaHero> Players2 { get; set; }
}
UPDATE:
For those interested in Dota, I lost all of my original code so I am rewriting and doing my best to make a tutorial out of it. http://uglyvpn.com/2014/07/21/dota-2-net-c-tool-pt1/

Make sure the list in Players2 is initialized properly. It could be done in your foreach loop, like this:
foreach (var match in matches.result.matches)
{
var _match = new MyDotaClass.MatchHistory();
_match.MatchID = match.match_id.ToString();
_match.Players2 = new List<MyDotaClass.DotaHero>();
...
But that's not a great design. It would be more robust to initialize it in the MatchHistory constructor, like this:
public class MatchHistory
{
public string MatchID { get; set; }
//public List<DotaHero> Players { get; set; }
public List<MyDotaClass.DotaHero> Players2 { get; private set; }
public MatchHistory() {
this.Players2 = new List<MyDotaClass.DotaHero>();
}
}
Note that I have also made the setter private here, as there should be no need to modify the value of this property after it's been initialized in the constructor.

It is look like your Players2 collection is not instantiated, so do it first:
this.Players2 = new List<MyDotaClass.DotaHero>();
and then you would be able to refer and use it:
_match.Players2.Add(_hero);
As for where to instantiate it, do it in the constructor of MatchHistory:
public MatchHistory() {
this.Players2 = new List<MyDotaClass.DotaHero>();
}
This is a good practice, because next time, even if you will forget to instantiate it, the constructor will do it automatically for you.
Otherwise, you'd keep getting: System.NullReferenceException
UPDATE:
You can't use this in a static context, change this method in order to enjoy from the constructor-base instantiating:
public static List<MyDotaClass.MatchHistory> GetMatchHistory(string uri)
to this:
public List<MyDotaClass.MatchHistory> GetMatchHistory(string uri)

You initialized the MatchHistory instance but not the Players2 property so it's still null.
You probably want to allocate it in the constructor like this although there are other options;
public MatchHistory()
{
Players2 = new List<MyDotaClass.DotaHero>();
}
PS LoL > Dota :p

Related

Filling POCO Object with List inside a List [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 6 years ago.
I´m attempting to fill a POCO object but I get the NullReferenceException - Object reference not set to an instance of an object, at line "objectAreas.position.Add(objectPositions);" I think I'm not initializing well but I don't see my mistake, let's see the code:
POCO OBJECT
public class GenericQuery
{
public sealed class Areas
{
public int idarea { get; set; }
public string areaname { get; set; }
public List<Positions> positions { get; set; }
}
public sealed class Positions
{
public int idposition { get; set; }
public string positionname { get; set; }
}
public sealed class QueryAreasPositions
{
public int code { get; set; }
public string response { get; set; }
public List<Areas> areas { get; set; }
}
}
Filling It
GenericQuery.QueryAreasPositions objectAreasPositions = new GenericQuery.QueryAreasPositions();
var query = areaRepository.Get(); //Eager Loading EntityFramework List Object, see the AreaRepository at the end
objectAreasPositions.code = 123;
objectAreasPositions.response = "anything";
foreach (var area in query)
{
GenericQuery.Areas objectAreas = new GenericQuery.Areas();
objectAreas.idarea = area.IdArea;
objectAreas.areaname = area.Name;
foreach (var position in area.Position)
{
GenericQuery.Positions objectPositions = new GenericQuery.Positions();
objectPositions.idposition = position.IdPosition;
objectPositions.positionname = position.Name;
***objectAreas.position.Add(objectPositions);***//HERE
}
objectAreasPositions.areas.Add(objectAreas); //And maybe here
}
AreaRepository
public List<Area> Get()
{
using (var context = new Entities())
{
return context.Area.Include("Position").ToList();
}
}
I would appreciate any help/guide you can give me, Thanks.
You are never initializing objectAreas.position, hence the default value for a List<T> is null.
Since you are trying to call the Add method on a null reference, you are getting a NullReferenceException.
To fix this, you should initialize the property before using it:
objectAreas.position = new List<GenericQuery.Positions>();
Alternatively, you can add this logic on GenericQuery.Areas constructor, which would be more appropriate:
public sealed class Areas
{
public int idarea { get; set; }
public string areaname { get; set; }
public List<Positions> positions { get; set; }
public class Areas()
{
positions = new List<Positions>();
}
}
Shouldn't you rather be doing like below. Your position is null cause not yet initialized and thus the said exception.
objectAreas.position = new List<Position>();
objectAreas.position.Add(objectPositions);

How to add object from a class to List in another class.

I am not sure I am asking this question properly and have had trouble searching for what I need in this case. I have two classes. One consists of three items that I will assign.
namespace Common.PriceFeed
{
public class SurchargeSKUList
{
public string WebSKUID { get; set; }
public decimal AdditionalPrice { get; set; }
public string Currency { get; set; }
}
}
The other class is a list containing the items from the above class.
namespace Common.PriceFeed
{
public class BaseSurcharge
{
public List<SurchargeSKUList> SKUList { get; set; }
}
}
My problem is, then I try to use BaseSurcharge, I get errors like I am using as type as a variable or that I "cannot implicitly convert type..."
My .net code is below.
Thank you.
if (BaseSurcharges.Rows.Count > 0)
{
foreach (DataRow row in BaseSurcharges.Rows)
{
SurchargeSKUList newSKUList = new SurchargeSKUList();
newSKUList.WebSKUID = row["WebSKUID"].ToString();
newSKUList.AdditionalPrice = Convert.ToDecimal(row["AdditionalPrice"]);
newSKUList.Currency = row["Currency"].ToString();
BaseSurcharge newSurcharge = new BaseSurcharge();
newSurcharge.SKUList = List<SurchargeSKUList>newSKUList;
//BaseSurcharge List<SurchargeSKUList> newSurcharge = new BaseSurcharge
//BaseSurcharge newSurcharge = new BaseSurcharge();
//newSurcharge.SKUList = newSKUList;
}
}
newSurcharge.SKUList = List<SurchargeSKUList>newSKUList;
should be changed to:
newSurcharge.SKUList = new List<SurchargeSKUList>();
newSurcharge.SKUList.Add(newSKUList);
I didn't check this out on Visual Studio. So it might have some syntax errors.
But better yet - BaseSurcharge should have SKUList = new List<SurchargeSKUList>(); in its constructor.

Values returned from class revert to null

I create an new Contractor object "gc" that calls a method GetContractor() to return all the properties. The results it is returning is correct, however the "gc" object shows all "NULL". I assume I doing something incorrectly in my aspx.cs page?
aspx.cs
protected void fvWasteCollected_ItemCommand(object sender, FormViewCommandEventArgs e)
{
if (e.CommandName.Equals("Insert")){
ValidationSummaryWasteDetail.ValidationGroup = "WasteReceivedDetail";
if (IsValid) {
odsMRWWasteCollectedDetail.InsertParameters["WasteTypeId"].DefaultValue = ddlWasteCollectedType.SelectedValue;
odsMRWWasteCollectedDetail.InsertParameters["DisposalMethodId"].DefaultValue = ddl_disposalMethod.SelectedValue;
Contractor gc = new Contractor();
gc.GetContractor(2);
var contractorName = gc.MRWContractorName;
}
}
}
.cs
public class Contractor
{
public Contractor GetContractor(int MRWContractorId)
{
using (DataAccessLINQDataContext db = new DataAccessLINQDataContext())
{
var result = db.MRWContractors.Where(c => c.MRWContractorId == MRWContractorId).Select(c => new Contractor
{
MRWContractorId = c.MRWContractorId,
MRWContractorName = c.MRWContractorName,
MRWContractorAddress = c.MRWContractorAddress,
MRWContractorCity = c.MRWContractorCity,
MRWContractorStateCode = c.MRWContractorStateCode,
MRWContractorZipCode = c.MRWContractorZipCode,
MRWContractorPhone = c.MRWContractorPhone,
MRWContractorFax = c.MRWContractorFax,
MRWContractorEmail = c.MRWContractorEmail
}).SingleOrDefault();
return result;
}
}
public int MRWContractorId { get; set; }
public string MRWContractorName { get; set; }
public string MRWContractorAddress { get; set; }
public string MRWContractorCity { get; set; }
public string MRWContractorStateCode { get; set; }
public int? MRWContractorZipCode { get; set; }
public string MRWContractorPhone { get; set; }
public string MRWContractorFax { get; set; }
public string MRWContractorEmail { get; set; }
}
You are loosing the value of gc when you dont assign it to something.
Try this instead:
var contractor = gc.GetContractor(2);
var contractorName = contractor.MRWContractorName;
You are creating one empty instance of the object that is only used to call the GetContractor method. The GetContractor method creates another instance that contains data, which is returned, but you just throw that instance away and expect the data to be available in the first instance that never got populated.
Make the GetContractor method static so that you don't need an instance to call it:
public static Contractor GetContractor(int MRWContractorId)
Now you can call the method to get that instance that contains the data, without first creating an empty instance:
Contractor gc = Contractor.GetContractor(2);
string contractorName = gc.MRWContractorName;

C# nested class/struct visibility

I'm trying to figure out what the proper syntax is to achieve a certain API goal, however I am struggling with visibility.
I want to be able to access a Messenger instance's member like msgr.Title.ForSuccesses.
However, I do not want to be able to instantiate Messenger.Titles from outside my Messenger class.
I'm also open to making Messenger.Titles a struct.
I'm guessing I need some sort of factory pattern or something, but I really have no idea how I'd go about doing that.
See below:
class Program {
static void Main(string[] args) {
var m = new Messenger { Title = { ForErrors = "An unexpected error occurred ..." } }; // this should be allowed
var t = new Messenger.Titles(); // this should NOT be allowed
}
}
public class Messenger {
// I've tried making this private/protected/internal...
public class Titles {
public string ForSuccesses { get; set; }
public string ForNotifications { get; set; }
public string ForWarnings { get; set; }
public string ForErrors { get; set; }
// I've tried making this private/protected/internal as well...
public Titles() {}
}
public Titles Title { get; private set; }
public Messenger() {
Title = new Titles();
}
}
You just need to make Titles private and expose an interface instead of it.
class Program {
static void Main(string[] args) {
var m = new Messenger { Title = { ForErrors = "An unexpected error occurred ..." } }; // this is allowed
var t = new Messenger.Titles(); // this is NOT allowed
}
}
public class Messenger {
public interface ITitles {
string ForSuccesses { get; set; }
string ForNotifications { get; set; }
string ForWarnings { get; set; }
string ForErrors { get; set; }
}
private class Titles : ITitles {
public string ForSuccesses { get; set; }
public string ForNotifications { get; set; }
public string ForWarnings { get; set; }
public string ForErrors { get; set; }
}
public ITitles Title { get; private set; }
public Messenger() {
Title = new Titles();
}
}
If you make the Titles constructor internal you will be able to create instances of it within your assembly only. If it is an API, perhaps that will be protected enough? You can see this pattern within the BCL (such as HttpWebRequest that can be created only through calls to WebRequest.Create).
Why Would I Ever Need to Use C# Nested Classes Nested type is never intended to be initialized from external type.
Well, you could make Titles a struct and make the constructor either public or internal. In that way, every time a client gets a copy of the Titles instance through the Title property, they will be getting the value, not the reference. They could modify that value, but to apply that change to the internal state of your object, they would need to be able to set the value back again through the Title property. They can't, because you have the Title setter marked private.
You will have to do the same when you change a value internally. For example:
// Your constructor...
public Messenger()
{
Titles t = new Titles();
t.ForSuccesses = "blah";
Title = t;
}
You can do this internally because you have access to the private setter for the Title property.
The main downside is that it might confuse the clients of your framework a bit because it looks like you can set the values of the Titles instance, but there is no real way for them to commit that change back to the Messenger class.

C# - copying property values from one instance to another, different classes

I have two C# classes that have many of the same properties (by name and type). I want to be able to copy all non-null values from an instance of Defect into an instance of DefectViewModel. I was hoping to do it with reflection, using GetType().GetProperties(). I tried the following:
var defect = new Defect();
var defectViewModel = new DefectViewModel();
PropertyInfo[] defectProperties = defect.GetType().GetProperties();
IEnumerable<string> viewModelPropertyNames =
defectViewModel.GetType().GetProperties().Select(property => property.Name);
IEnumerable<PropertyInfo> propertiesToCopy =
defectProperties.Where(defectProperty =>
viewModelPropertyNames.Contains(defectProperty.Name)
);
foreach (PropertyInfo defectProperty in propertiesToCopy)
{
var defectValue = defectProperty.GetValue(defect, null) as string;
if (null == defectValue)
{
continue;
}
// "System.Reflection.TargetException: Object does not match target type":
defectProperty.SetValue(viewModel, defectValue, null);
}
What would be the best way to do this? Should I maintain separate lists of Defect properties and DefectViewModel properties so that I can do viewModelProperty.SetValue(viewModel, defectValue, null)?
Edit: thanks to both Jordão's and Dave's answers, I chose AutoMapper. DefectViewModel is in a WPF application, so I added the following App constructor:
public App()
{
Mapper.CreateMap<Defect, DefectViewModel>()
.ForMember("PropertyOnlyInViewModel", options => options.Ignore())
.ForMember("AnotherPropertyOnlyInViewModel", options => options.Ignore())
.ForAllMembers(memberConfigExpr =>
memberConfigExpr.Condition(resContext =>
resContext.SourceType.Equals(typeof(string)) &&
!resContext.IsSourceValueNull
)
);
}
Then, instead of all that PropertyInfo business, I just have the following line:
var defect = new Defect();
var defectViewModel = new DefectViewModel();
Mapper.Map<Defect, DefectViewModel>(defect, defectViewModel);
Take a look at AutoMapper.
There are frameworks for this, the one I know of is Automapper:
http://automapper.codeplex.com/
http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/01/22/automapper-the-object-object-mapper.aspx
Replace your erroneous line with this:
PropertyInfo targetProperty = defectViewModel.GetType().GetProperty(defectProperty.Name);
targetProperty.SetValue(viewModel, defectValue, null);
Your posted code is attempting to set a Defect-tied property on a DefectViewModel object.
In terms of organizing the code, if you don't want an external library like AutoMapper, you can use a mixin-like scheme to separate the code out like this:
class Program {
static void Main(string[] args) {
var d = new Defect() { Category = "bug", Status = "open" };
var m = new DefectViewModel();
m.CopyPropertiesFrom(d);
Console.WriteLine("{0}, {1}", m.Category, m.Status);
}
}
// compositions
class Defect : MPropertyGettable {
public string Category { get; set; }
public string Status { get; set; }
// ...
}
class DefectViewModel : MPropertySettable {
public string Category { get; set; }
public string Status { get; set; }
// ...
}
// quasi-mixins
public interface MPropertyEnumerable { }
public static class PropertyEnumerable {
public static IEnumerable<string> GetProperties(this MPropertyEnumerable self) {
return self.GetType().GetProperties().Select(property => property.Name);
}
}
public interface MPropertyGettable : MPropertyEnumerable { }
public static class PropertyGettable {
public static object GetValue(this MPropertyGettable self, string name) {
return self.GetType().GetProperty(name).GetValue(self, null);
}
}
public interface MPropertySettable : MPropertyEnumerable { }
public static class PropertySettable {
public static void SetValue<T>(this MPropertySettable self, string name, T value) {
self.GetType().GetProperty(name).SetValue(self, value, null);
}
public static void CopyPropertiesFrom(this MPropertySettable self, MPropertyGettable other) {
self.GetProperties().Intersect(other.GetProperties()).ToList().ForEach(
property => self.SetValue(property, other.GetValue(property)));
}
}
This way, all the code to achieve the property-copying is separate from the classes that use it. You just need to reference the mixins in their interface list.
Note that this is not as robust or flexible as AutoMapper, because you might want to copy properties with different names or just some sub-set of the properties. Or it might downright fail if the properties don't provide the necessary getters or setters or their types differ. But, it still might be enough for your purposes.
This is cheap and easy. It makes use of System.Web.Script.Serialization and some extention methods for ease of use:
public static class JSONExts
{
public static string ToJSON(this object o)
{
var oSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
return oSerializer.Serialize(o);
}
public static List<T> FromJSONToListOf<T>(this string jsonString)
{
var oSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
return oSerializer.Deserialize<List<T>>(jsonString);
}
public static T FromJSONTo<T>(this string jsonString)
{
var oSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
return oSerializer.Deserialize<T>(jsonString);
}
public static T1 ConvertViaJSON<T1>(this object o)
{
return o.ToJSON().FromJSONTo<T1>();
}
}
Here's some similiar but different classes:
public class Member
{
public string Name { get; set; }
public int Age { get; set; }
public bool IsCitizen { get; set; }
public DateTime? Birthday { get; set; }
public string PetName { get; set; }
public int PetAge { get; set; }
public bool IsUgly { get; set; }
}
public class MemberV2
{
public string Name { get; set; }
public int Age { get; set; }
public bool IsCitizen { get; set; }
public DateTime? Birthday { get; set; }
public string ChildName { get; set; }
public int ChildAge { get; set; }
public bool IsCute { get; set; }
}
And here's the methods in action:
var memberClass1Obj = new Member {
Name = "Steve Smith",
Age = 25,
IsCitizen = true,
Birthday = DateTime.Now.AddYears(-30),
PetName = "Rosco",
PetAge = 4,
IsUgly = true,
};
string br = "<br /><br />";
Response.Write(memberClass1Obj.ToJSON() + br); // just to show the JSON
var memberClass2Obj = memberClass1Obj.ConvertViaJSON<MemberV2>();
Response.Write(memberClass2Obj.ToJSON()); // valid fields are filled
For one thing I would not place that code (somewhere) external but in the constructor of the ViewModel:
class DefectViewModel
{
public DefectViewModel(Defect source) { ... }
}
And if this is the only class (or one of a few) I would not automate it further but write out the property assignments. Automating it looks nice but there may be more exceptions and special cases than you expect.
Any chance you could have both classes implement an interface that defines the shared properties?

Categories

Resources