C# - Using a model that contains a model of arrays - c#

I have this model that I am trying to reference and get the an array of this type.
public class TestModel
{
public string Name { get; set; }
public Guid Id { get; set; }
public List<Conditions> Conditions { get; set; }
}
I also need to get the conditions for this which is a separate model with a few arrays.
public class Conditions
{
public List<string> Country { get; set; }
public List<int> Grades { get; set; }
public List<string> Disciplines { get; set; }
}
I can get the Name and Id easily enough but when I try and get the values in any of the arrays I get an error Object reference not set to an instance of an object. which it would normally give as the array is not instantiated. Is there any way to do this without instantiating the array?
Code I am using to get the Id
private static ArrayList GetTests()
{
Console.WriteLine("Get tests");
foreach (TestModel test in testModel)
{
var conditions = test.Conditions.Disciplines;
Console.WriteLine("");
Console.WriteLine("testID: " + test.Id);
}
return networks;
}
The model is populated in the main method:
private static IEnumerable<TestModel> testModel= new TestModel[] { };
public static void Main(string[] args)
{
Console.WriteLine("Start");
Console.WriteLine("Load Test Data");
using (var r = new StreamReader(#"C:\Production\test.json"))
{
string json = r.ReadToEnd();
testModel = JsonConvert.DeserializeObject<TestModel[]>(json);
}
GetTests();
Console.WriteLine("End");
Console.Read();
}
I feel like this should be populated when the Json file is read and put into the model.

As you said: You did not instantiate the arrays.
You could for example do it in the constructor, use the setters or simply do it inline (C# 6.0 required):
public class Conditions
{
public string[] Country { get; set; } = new string[length];
public int[] Grades { get; set; } = new int[length];
public string[] Disciplines { get; set; } = new string[length];
}
"length" is the length of the array. If you don't know the size, you might consider using a List<> or something like that.

Switching to List for each of the properties worked. I shall edit the code above with the correct answer, Thanks to #Thomas D. for pointing me in that direction

Related

Adding thing to list in object in c#

I'm trying to add a string to an object in c# like this:
The class is:
class thing
{
public int somenumber { get; set; }
public int someothernumber { get; set; }
public List<string> words { get; set; }
}
I'm trying to do
var something = new thing();
something.words.Add("some word");
How do I add a string to the list 'words' without getting nullreference-errors?
Initialize words list in the constructor of the class, to make sure that it will exist.
public YourClass {
words = new List<string>;
}
Add new item to that list in the corresponding method.
public void YourMethod {
words.Add("New Item");
}
You have first to create a list, since by default words would be null.
var something = new thing();
something.words = new List<string>();
Then you can use the newly created list, as you have already done:
something.words.Add("some word");
Now when something.words would point to the newly created list and it wouldn't be null.
Another more consistent way to do this, is to create that list in the class constructor:
public class Thing
{
public int SomeNumber { get; set; }
public int SomeOtherNumber { get; set; }
public List<string> Words { get; set; }
public Thing()
{
Words = new List<string>();
}
}
btw, please also look at the naming conventions (e.g. properties name start with capital letters as well as class names).
Update
As correctly matthew-watson mentioned in his comments, there is also another way (probably better) for doing the same thing:
public class Thing
{
public int SomeNumber { get; set; }
public int SomeOtherNumber { get; set; }
public List<string> Words { get; } = new List<string>();
}
Doing so, we create a read-only list. Essentially when we create an instance of this class a new list of strings is created and it's reference is assigned to the Words backing field. From that moment, you can't change the reference that is stored in that backing field and you can use the list only for adding/removing things, you can't change it's reference.

Can you declare a List of a class within another class?

I am trying to create a simple order sheet that has products, customers, order lines, and an order sheet. Currently, I am just hardcoding in products and customers for simple testing purposes. With the order sheet, I want to have a List of the order line items (contains quantity and price from products, and a few other bits of information) in the order class. When I create the order in the program, it's not creating the List of order line items that I have in the constructor. I have tried to .Add within the constructor which didn't work as well in the program, in the program it states it does not contain the definition Add.
When I try to access .test it shows as NULL.
namespace ObjectsCSharpe.Library
class Order
{
public Order()
{
var testLine = new List<OrderLineItems>();
}
public List<OrderLineItems> testLine { get; set; }
}
class OrderLineItems
{
public OrderLineItems()
{
this.orderID = 0;
this.lineNumber = 0;
this.product = new Product();
this.quantity = 0;
this.test = "OLI";
this.lineTotal = 0.00;
}
public int orderID { get; set; }
public int lineNumber { get; set; }
public Product product { get; set; }
public int quantity { get; set; }
public string test { get; set; }
public double lineTotal { get; set; }
}
class Program
{
static void Main(string[] args)
{
Order orderSheet = new Order();
OrderLineItems temp456 = new OrderLineItems();
orderSheet.testLine.Add(temp456);
string abc = orderSheet.testLine[0].test;
Console.WriteLine(abc);
}
}
I'll start with this excerpt:
public Order()
{
var testLine = new List<OrderLineItems>();
}
This is the constructor for the Order type. In this code, the var keyword means you are declaring a new variable, where the scope of the variable is limited to that method. The type also contains this:
public List<OrderLineItems> testLine { get; set; }
So there is a separate testLine variable in the type. But, in the constructor, the use of var means this other variable was not touched.
Later on we have this code:
orderSheet.testLine.Add(temp456);
Unfortunately, because of the earlier mistake, orderSheet.testLine is still null, and you can't call a method on a null reference.
You can fix this as easily as removing var from the constructor:
public Order()
{
testLine = new List<OrderLineItems>();
}
or, even better, remove the entire constructor from the type completely. Initialize the list property where it is declared and make it get-only:
public class Order
{
public List<OrderLineItems> testLine {get;} = new List<OrderLineItems>();
}
(Note: You can still add items to get-only List property.)
I think you need to make public keyword while creating all your class.
public class Order{
//Add Your class declaration...
}

Assignment same property values to other

I have different classes sharing some properties of same type and name. I wish to assign same property values to each other. I explain my intention better in comments in the following pseudo-code. Is it possible in C#?
Ponder that there are a plethora of common properties but in unrelated classes, must we assign them one-by-one?
Second case is about sharing same properties but some of them may be nullable, who knows!
Side note: the classes already exist, cannot be altered, touched. Kinda sealed.
Can't it be done using nameofoperator and two for loops? Compare property names if matched, assign?
using System;
namespace MainProgram
{
class HomeFood
{
public DateTime Date { get; set; }
public string food1 { get; set; }
public string food2 { get; set; }
public int cucumberSize { get; set; }
}
class AuntFood
{
public string food2 { get; set; }
public int cucumberSize { get; set; }
public DateTime Date { get; set; }
public string food1 { get; set; }
// extra
public double? length { get; set; }
}
class GrandpaFood
{
public string? food2 { get; set; }
public int cucumberSize { get; set; }
public DateTime? Date { get; set; }
public string food1 { get; set; }
// extra
}
static class Program
{
public static void Main(string[] args)
{
var home = new HomeFood
{
Date = new DateTime(2020, 1, 1),
food1 = "cucumber",
food2 = "tomato",
cucumberSize = 123
};
var aunt = new AuntFood();
/*
First case: same types
Expected for-each loop
assigning a class's property values
to other class's property values
or for-loop no matter
foreach(var property in HomeFood's properties)
assign property's value to AuntFood's same property
*/
var home2 = new HomeFood();
var grandpa = new GrandpaFood
{
Date = new DateTime(2020, 1, 1),
food1 = "dfgf",
food2 = "dfgdgfdg",
cucumberSize = 43534
};
/*
Second case: similar to first case
with the exception of same type but nullable
or for-loop no matter
foreach(var property in GrandpaFood's properties)
assign property's value to GrandpaFood's same property
we don't care if it is null e.g.
Home2's same property = property's value ?? default;
*/
}
}
}
Based on the comments in the questions, this is just to show how it can be done with reflection.
Disclaimer, this is just a very simplified example on how to use reflection to sync properties. It does not handle any special cases (modifiers, read only, type mismatch, etc)
I would strongly suggest to use automapper to achieve the qp goals.
public class Type1
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
public class Type2
{
public string Property1 { get; set; }
public string Property3 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var t1 = new Type1 { Property1 = "Banana" };
var t2 = new Type2();
var properties1 = typeof(Type1).GetProperties().ToList();
var properties2 = typeof(Type2).GetProperties().ToList();
foreach(var p in properties1)
{
var found = properties2.FirstOrDefault(i => i.Name == p.Name);
if(found != null)
{
found.SetValue(t2, p.GetValue(t1));
}
}
Console.WriteLine(t2.Property1);
}
}
The short answer is, apply OOP. Define a base Food class and inherit from it in any specific food classes you have. You can put all the shared props in the base class.
public class Food
{
public string food2 { get; set; }
// other shared stuff
}
class GrandpaFood : Food
{
// other specific stuff
}
As others have said, use some of the Object Oriented properties, like inheriting a super class of implement an interface.
In case you go for inheritance, consider making the super class (the one you inherit from) abstract. This means that the super class itself cannot be instantiated, which greatly reduces the risk of violating the Liskov Substitutional Principle. Also it often reflects the real problem better. In your example, this would also be the case, as “food” is not an actual thing in the real world, but rather a group of things.

unable to get list of elements in list

i have 2 model classes
public class ProductOptionRequest
{
public string Name { set; get; }
public List<ProductValuesRequest> productValues { get; set; }
}
public class ProductValuesRequest
{
public string ValueName { get; set; }
}
public class ProductOptionValue
{
public int OptionId { get; set; }
public String ValueName { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
and wrote one bs method and passing parameter value as value names. but I'm unable to get those values in a list object as productValues. May I know the solution, please.
public async Task<ReturnString> SaveProductOption(ProductOptionRequest request)
{
request.productValues = new List<ProductValuesRequest>();
foreach (ProductValuesRequest valueRequest in request.productValues)
{
ProductOptionValue res = new ProductOptionValue();
res.ValueName = valueRequest.ValueName;
object response = await productOptionValueRepository.InsertAsync(res, true);
}
}
In the first line of your method, you are replacing the productValues property of request object with a new empty list, :
request.productValues = new List<ProductValuesRequest>();
Therefore, in foreach loop, you are iterating on an empty list.
Remove the first line and see if you still have any issues.
You are assigning an emplty list to productValues as
request.productValues = new List() and trying to iterate the empty list.

"Value does not fall within the expected range" exception in ListView

For Windows 8 application development environment.
Code:
var deserialized = JsonConvert.DeserializeObject<RootObject>(json);
listView.ItemsSource = deserialized; // error
Data model:
public class C
{
public List<Y> programs { get; set; }
public string name { get; set; }
public int code { get; set; }
}
public class RootObject
{
public List<C> cs { get; set; }
public string date { get; set; }
}
public class Y
{
public string category { get; set; }
public string time { get; set; }
public string name { get; set; }
}
What can I do ? I don't find solution.
ItemsSource is looking for an IEnumerable, but you're providing a single object in RootObject. You'd get the same error if you create one of your RootObject instances in code and try the same assignment.
What specifically should be displaying in the list? If you simply change your code to:
listView.ItemsSource = deserialized.cs;
the listView should display your C objects.
I always have trouble figuring out how to go from the serializer output. I do have working code (windows 8 store) that I'm pasting below. It is pretty obvious what it does.
HttpResponseMessage responseGetEmailByPersonsBare =
await clientGetEmailByPersonsBare.PostAsync(UrlBase + EmailDetailGetEmailByPersonsBare, contentGetEmailByPersonsBare);
Stream myStream = await responseGetEmailByPersonsBare.Content.ReadAsStreamAsync();
var djsGetEmailByPersonsBare = new DataContractJsonSerializer(typeof(AEWebDataStructures.RootObjectEmailDetail));
var rootObjectEmailDetail = (AEWebDataStructures.RootObjectEmailDetail)djsGetEmailByPersonsBare.ReadObject(myStream);
responseGetEmailByPersonsBare.EnsureSuccessStatusCode();
returnTaskInfo.EmailDetails = rootObjectEmailDetail.Data;
returnTaskInfo.StatusReturn = AEWebDataStructures.StatusReturn.Success;

Categories

Resources