I have a class that I am populating with a view to serializing into JSON
My class has strings and one IEnumerable of a second class (Icons)
public class ManifestModel
{
public string ShortName { get; set; }
public string Name { get; set; }
public IEnumerable<Icon> Icons { get; set; }
public string BackgroundColour { get; set; }
public string ThemeColour { get; set; }
public class Icon
{
public string Src { get; set; }
public string Type { get; set; }
public string Sizes { get; set; }
}
}
When creating an instance of ManifestModel, it is easy enough to populate the string properties, but how do I add my two icon variables (icon192 and icon512)?
var icon192 = new ManifestModel.Icon
{
Src = "192",
Type = "images/png",
Sizes = "192x192"
};
var icon512 = new ManifestModel.Icon
{
Src = "512",
Type = "images/png",
Sizes = "512x512"
};
var manifestModel = new ManifestModel
{
ShortName = siteRoot.GetValue<string>("siteTitle"),
Name = siteRoot.GetValue<string>("siteName"),
//how to add two Icon objects here
};
I have tried
Just create an array and assign to Icons property.
var manifestModel = new ManifestModel
{
Icons = new[] { icon192, icon512 },
//...
Because Icons is an IEnumerable, you can create a list
var manifestModel = new ManifestModel
{
Icons = new List<ManifestModel.Icon>() { icon192, icon512 },
//do something
It is uncommon to use a read/write property to maintain a list of items in an object. What you generally want is a solution, where you can just write:
foreach (Icon icon in model.Icons) {
//Do something
}
With a read/write property, Icons can be null and the result will be a NullReferenceException.
What is even worse is that you will add the potential for subtle bugs. When you start iterating over Icons and you set the value during the iteration, you might expect that you are continuing to iterate over the new list. This is not the case though, you're still iterating over the previous value. Usually in these cases the original iteration should fail with an InvalidOperationException upon continuation.
To avoid this problem, use a collection that is derived from System.Collections.ObjectModel.Collection<T> and expose it as a property:
public class IconCollection : Collection<Icon> {
//Customize here
}
public class ManifestModel
{
//
public IconCollection Icons { get; } = new IconCollection();
//...
}
When you want to add items you go:
model.Icons.Add(icon);
This will avoid the problems described above.
Related
I have three classes:
public class M2ArticleMain
{
public int Id { get; set; }
public List<M2ArticleAttributeWeb> Attribut_Web { get; set; }
}
public class M2ArticleAttributeWeb
{
public int Web_Id { get; set; }
public M2ArticleTmpMainSkus Variants { get; set; }
}
public class M2ArticleTmpMainSkus
{
public DateTime TimeAdded { get; set; }
public List<string> Skus { get; set; }
}
And I have two Lists in my code like this:
List<M2ArticleMain> data = new List<M2ArticleMain>();
List<M2ArticleAttributeWeb> attb = new List<M2ArticleAttributeWeb>();
In some part of my code firstly I (from foreach loop) add data to attb list where I add only only some data (because I don't have all data at this point), like this:
...
attb.Add(new M2ArticleAttributeWeb
{
Web_id = item.Id, //(item is from foreach loop)
Variants = null //this is **importat**, I left null for later to add it
});
Next, after I fill attb, I add all this to data list:
...
data.Add(new M2ArticleMain
{
Id = item.Id_Pk, //this is also from foreach loop,
Attribut_Web = attb //now in this part I have only data for Web_id and not Variants
}
Now my question is How to Add items later to data list to object Variants?
Something like this:
data.AddRange( "how to point to Variants" = some data);
The M2ArticleAttributeWeb type holding your Variants property is the member of a collection. That is, there are potentially many of them. You can reference an individual Variants property like this:
data[0].Attribut_Web[0].Variants
But you need to know which items you want to add map to which data and Attribut_Web indexes/objects in order to assign them properly. That probably means another loop, or even a nested loop. That is, you can see all of your Variants properties in a loop like this:
foreach(var main in data)
{
foreach(var attrw in main)
{
var v = attrw.Variants;
// do something with v
Console.WriteLine(v);
// **OR**
attrw.Variants = // assign some object
}
}
It's also much better practice to create your collection properties with the object, and then give them private set attributes:
public class M2ArticleMain
{
public int Id { get; set; }
public List<M2ArticleAttributeWeb> Attribut_Web { get; private set; } = new List<M2ArticleAttributeWeb>();
}
public class M2ArticleAttributeWeb
{
public int Web_Id { get; set; }
public M2ArticleTmpMainSkus Variants { get; set; }
}
public class M2ArticleTmpMainSkus
{
public DateTime TimeAdded { get; set; }
public List<string> Skus { get; private set; } = new List<string>();
}
Now instead of assigning Attribut_Web = attb, you would need to .Add() to the existing List.
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
I have a class with this:
public class myDataType
{
public class GetInvoice
{
public string InvoiceID { get; set; }
public string InvoiceNumber { get; set; }
public decimal InvoiceAmount { get; set; }
public List<InvoiceRow> Rows { get; set; }
}
public class InvoiceRow
{
public decimal RowQty { get; set; }
public string RowCode { get; set; }
public string RowDescription { get; set; }
}
}
And when I want to add data has th
using static test.myDataType;
...
private void LoadData()
{
GetInvoice Invoice = new GetInvoice();
Invoice.InvoiceID = "0a8625e5-62f6-4ad7-a8bf-ab04b1158392";
Invoice.InvoiceNumber = "Inv-001";
Invoice.InvoiceAmount = 100;
Invoice.Rows.Add(new InvoiceRow { RowQty= 1, RowCode = "C100", RowDescription = "Item C100"});
}
When try to add the row:
Invoice.Rows.Add(new InvoiceRow { RowQty= 1, RowCode = "C100",
RowDescription = "Item C100"});
Show me this error "System.NullReferenceException: 'Object reference not set to an instance of an object'"
I think i have a sintax o wrong way to do it
Can someone help?
Thanks in advance
It's not a syntax error, you just haven't initialised the list.
With
public List<InvoiceRow> Rows { get; private set; }
you've declared a place to hold the list, but haven't created the list itself.
(If an analogy helps, imagine you've drawn a line on the wall of your house where you're going to put up a bookshelf, but you haven't actually screwed the shelf to the wall yet - that's the situation your code is in).
If you want the list to always be available you can either initialise it automatically through the property declaration, or in the constructor of the class. Alternatively of course you could leave the calling code to initialise it.
This version just makes it part of the property declaration:
public List<InvoiceRow> Rows { get; private set; } = new List<InvoiceRow>();
You need first to initialize list Rows before you add element to it.
For example in GetInvoice class you can add:
public List<InvoiceRow> Rows { get; set; } = new List<InvoiceRow>();
List is reference type in C# so it needs to be initialized before being used.
If you want to do that in LoadData() method you can do in this way:
private void LoadData()
{
GetInvoice Invoice = new GetInvoice();
Invoice.InvoiceID = "0a8625e5-62f6-4ad7-a8bf-ab04b1158392";
Invoice.InvoiceNumber = "Inv-001";
Invoice.InvoiceAmount = 100;
Invoice.Rows = new List<InvoiceRow>();
Invoice.Rows.Add(new InvoiceRow { RowQty = 1, RowCode = "C100", RowDescription = "Item C100" });
}
I have this class in C#:
public class Init
{
public string First_name { get; set; }.
public List<LeadLocations> Locations { get; set; }
}
public Init()
{
this.Locations = new List<LeadLocations>();
}
public class LeadLocations
{
public string City { get; set; }
public string State { get; set; }
public string County { get; set; }
}
I need to fill Locations with values that I have in another list like:
foreach (var item2 in AreaOfInterest.AreaOfInterests)
{
foreach (var item in transactionInit.Locations)
{
item.City = item2.City;
item.County = item2.County;
}
}
but it never goes to second foreach as it is empty. How I can initialize it to new object, anything I try is not working.
If you are trying to add location to a list of locations, you need to create a new location object (based on the AreaOfInterests objects) and then add that to the list of locations.
// Initialize your Locations if its not already initialized.
// If its not initialized, you will get Object Reference Not Set to Instance of an Object.
transactionInit.Locations = new List<LeadLocations>();
foreach (var item2 in AreaOfInterest.AreaOfInterests)
{
// For Each item2, create a new location then insert it in transactionInit.Locations.
var leadLocation = new LeadLocation() {City = item2.City, County = item2.County};
transactionInit.Locations.Add(leadLocation);
}
I believe I understood what you are intending to do. You could do the following.
transactionInit.Locations.AddRange(AreaOfInterest.AreaOfInterests
.Select(x=> new Location
{
City = x.City,
County=x.County
});
In the above code, you are iterating over the AreaOfInterest.AreaOfInterests to create instances of Location and using the List.AddRange(IEnumerable<T>) to add them to the Locations property of transactionInit.
I need a clear example that shows me how to define a list that has n rows and 4 columns and how to use it. I need a list to save my data like the below image. as you see this could be a dictionary.
You need to create a class with all the above properties
public class Sample
{
public string vocabulary { get; set; }
public string meaning { get; set; }
public int number { get; set; }
public int group { get; set; }
}
and then you can create a List of type Sample,
List<Sample> yourList = new List<Sample>();
You can add items to the list as below
yourList.Add(new Sample { vocabulary = "massive", meaning = "very big", number = 5, group = 15 });
You can access them later like this, if you want the first element,
var result = yourList[0];
this is the easiest and best way of doing it. You need to create a new class and then create new instances of the class and then add it to the list and then use LINQ to get the data out
void Main()
{
var list = new List<myClass>()
list.Add(new myClass() {
Vocabluary = "Vocabluary ",
Meaning = "meaning",
Number = 1,
Group = 2})
}
public class myClass
{
public string Vocabluary { get; set; }
public string Meaning { get; set; }
public int Number { get; set; }
public int Group { get; set; }
}
yes... as Sajeetharan mentioned, with a custom class you can create an any dimensions List. but i don't think you need to think about dimension in C#... it is a bit more high level than that.
just simply create a class and put everything you need in it...
public class CustomClass{
public string d1;
public int d2;
public string d3;
public string d4;
...
//you can easily create a N dimension class
}
to access it and apply it
public void Main(){
List<CustomClass> list = new List<CustomClass>();
CustomClass cc = new CustomClass();
cc.d1 = "v1";
cc.d2 = 0; //v2
list.Add(cc);
//to access it
foreach(CustomClass tmpClass in list)
{
string d1Value = tmpClass.d1;
int d2Value = tmpClass.d2;
}
}
I have 2 classes with different properties in each. Also I have a collection of one set of objects of the class A. Now I want to copy these to an array of objects of Class B.
The 2 classes are not inter related and also the fields are different in each. SO i have to explicitly map the fields i want to copy. Right now I am using a foreach to copy individual element. Is there a shorter way to accomplish this.
This is the class B
public class Event
{
public string EventOriginTime { get; set; }
public string EventReceivedTime { get; set; }
public int EventCode { get; set; }
public string CardNumber { get; set; }
public string ReaderName { get; set; }
}
First class A also will appear something like this but that is a 3rd party class.
Current solution I have is:
List<Event> listOfEvents = new List<Event>();
foreach (var eachEvent in eventsFromArgus)
{
listOfEvents.Add( new Event
{
ReaderName = eachEvent.DeviceName,
EventCode = eachEvent.EventCode,
EventReceivedTime = eachEvent.ReceiveTime.ToString(),
EventOriginTime = eachEvent.OriginTime.ToString(),
CardNumber = eachEvent.CredentialIdentifier
});
}
You could use LINQ:
List<event> listOfEvents =
(from eachEvent in eventsFromArgus
select new Event(
ReaderName = eachEvent.DeviceName,
EventCode = eachEvent.EventCode,
EventReceivedTime = eachEvent.ReceiveTime.ToString(),
EventOriginTime = eachEvent.OriginTime.ToString(),
CardNumber = eachEvent.CredentialIdentifier)).ToList();
But that's not terribly different from what you already have.
Or, you could look into something like AutoMapper.
Another approach is to pass the third party object directly into the Event class' constructor:
public class Event
{
private readonly ThirdPartyClass _eventFromArgus;
public Event(ThirdPartyClass eventFromArgus)
{
_eventFromArgus = eventFromArgus;
}
public string ReaderName { get { return _eventFromArgus.DeviceName; } }
// etc.
}
Then you can just do this:
var listOfEvents = eventsFromArgus.Select(eachEvent => new Event(eachEvent));
also with linq as Jim suggested but a bit different
var listOfEvents = eventsFromArgus.Select(eachEvent =>
new Event( ReaderName = eachEvent.DeviceName,
EventCode = eachEvent.EventCode,
EventReceivedTime = eachEvent.ReceiveTime.ToString(),
EventOriginTime = eachEvent.OriginTime.ToString(),
CardNumber = eachEvent.CredentialIdentifier)).ToList();
You could add a constructor to the Event class:
public Event(string EventOriginTime, string EventReceivedTime, int EventCode, string CardNumber, string ReaderName)
{
this.EventOriginTime = EventOriginTime;
this.EventReceivedTime = EventReceivedTime;
this.EventCode = EventCode;
this.CardNumber = CardNumber;
this.ReaderName = ReaderName;
}
Then at least you don't have to specify the field names when creating a new instance.
List<Event> listOfEvents = new List<Event>();
foreach (var eachEvent in eventsFromArgus)
{
listOfEvents.Add(new Event(eachEvent.OriginTime.ToString(), eachEvent.ReceiveTime.ToString(), eachEvent.EventCode, eachEvent.DeviceName)
}