Convert List<string> to Model class - c#

Having issue with converting List to Student object in c#.
I have a C# model class as below:
public class Student{
public int ID{get;set;}
public string StudentName{get; set;}
public string StudentAddress{get; set;}
public string StudentRemarks{get; set;}
public string AdditionalInfo{get;set;}
}
I have another class where I have a List which holds data as below (Since this is just a list of string, it won't have any property names in front of it such as 'ID: 001') Note: This string will not have any data for 'AdditionalInfo'.
001
John, Snow
NewYork
Sample test info
Now I have another class where I wanted to convert this List to my 'Student' class where 001 has to be assigned to ID, John Snow has to be assigned to 'StudentName', NewYork has to be assigned to 'StudentAddress', Sample test info has to be assigned to 'StudentRemarks'. Since this doesn't have any data provided for 'AdditionalInfo' property, this should be assigned with empty or null value in it. Here is the class
public class StudentInfoService
{
public List<string> GetStudentInfo(string data)
{
var studentData = new List<string>();
foreach (var line in File.ReadLines(data))
{
if (!string.IsNullOrWhiteSpace(line))
{
var data = line.Split('|');
foreach (var item in data)
{
studentData.Add(item);
}
studentData.ConvertAll(c => (Student)c); //Here is where I am struggling to convert the list string to model class
}
}
return studentData ;
}
}
The issue is, I want to convert the list to 'Student' object and automatically assign all the data to the respective properties by order(there won't be any null or empty data in between other than the 'AdditionalInfo'). Student object will have only one student record. It won't have a list of records. So I need to convert the List to Student object. Please help me with this.

You will need to write code to map lines of text to a model instance, e.g.
public Student GetStudent(List<string> list)
{
return new Student
{
ID = int.Parse(list[0]),
StudentName = list[1],
StudentAddress = list[2],
StudentRemarks = list[3],
AdditionalInfo = (list.Count > 4) ? list[4] : null
};
}

Related

Invoke a static class list by reflection C#

I have a series of C# static lists in an API project that are very similar to the simple example defined here.
using System.Collections.Generic;
namespace myproject.api.PropModels
{
public class CommonSelectOptionsYesNoItem
{
public int Id { get; set; }
public string Title { get; set; }
}
public static class CommonSelectOptionsYesNo
{
public static readonly List<CommonSelectOptionsYesNoItem> Table = new List<CommonSelectOptionsYesNoItem>
{
new CommonSelectOptionsYesNoItem { Id = 0, Title = "No",},
new CommonSelectOptionsYesNoItem { Id = 1, Title = "Yes",},
};
}
}
These models establish a common information reference between a Javascript web application and the API that services the application.
User's are uploading spreadsheet data to the API that includes the list class name and the Title of an item in the list. I need to be able to determine what Id is associated with the Title - if any.
For example I know that this the information is in the list CommonSelectOptionsYesNo.Table and the Title property is "Yes". I can therefore determine that the the Id is 1.
In principle I can set up a switch / case method that picks the list identified as CommonSelectOptionsYesNo.Table and then gets the Id value. There are however than 60 of these reference lists and they keep growing.
Can I use reflection to invoke an instance of the readonly static list based on the the static class object name - in this example CommonSelectOptionsYesNo.Table?
After further research have worked out the following method to call up the static readonly list and return the Id for any given "Title" value.
The propModelKey is stored with the static list class in a dictionary of all the lists.
The list can be extracted as an object - knowing that the list is always declared with the property name "Table".
The properties of the list objects can vary depending on the purpose of the list but they always have the "Id" and "Title" properties. Serializing and deserializing the object with the simple class object "SelectOptions" generates a list that can be queried to extract the Id corresponding to the Title string submitted.
// This will return an Id of 1 from the simple YesNo list
var id = GetSelectListIndex("QuestionOneId", "Yes");
// Method to extract the Id of a value in a list given the list model key
private static int? GetSelectListIndex(string propModelKey, string title)
{
if (SelectListModelMap.ContainsKey(propModelKey))
{
var model = SelectListModelMap[propModelKey];
var typeInfo = Type.GetType("myproject.api.PropModels." + model).GetTypeInfo();
var fieldInfo = typeInfo.DeclaredFields.FirstOrDefault(x => x.Name == "Table");
var json = JsonConvert.SerializeObject(fieldInfo.GetValue(new object()));
var dictionary = JsonConvert.DeserializeObject<List<SelectOptions>>(json);
var index = dictionary.FirstOrDefault(x => x.Title == title)?.Id;
return index;
}
return null;
}
// Dictionary of lists with model key and class name
public static Dictionary<string, string> SelectListModelMap => new Dictionary<string, string>
{
{ "QuestionOneId", "CommonSelectOptionsYesNo" },
{ "CountryId", "CommonSelectOptionsCountries" },
// ... other lists
};
// generic class to extract the Id / Title pairs
public class SelectOptions
{
public int Id { get; set; }
public string Title { get; set; }
}

Is there a way to read a txt file into a list without using List<String>?

I am trying to read a .txt file into a list without using a List<string> type. I have created a separate class, called Club, that does all of the sorting. However, I am having difficulties actually reading in the .txt file.
string path = "C:\\Users\\Clubs-2019";
public List<Club> ReadClubsTxtFile()
{
List<Club> outcome = new List<Club>();
string[] text = File.ReadAllLines(path);
outcome.Add(text);
return outcome;
}
The line outcome.Add(text); shows an error as I am trying to send the wrong type to the list.
This is a sample of the text file:
Club Name Club Number Meeting Address Latitude Longitude Meeting Day Meeting Time Meeting End Time
Alabaster-Pelham 4018 1000 1st St North Alabaster AL 35007 33.252414 -86.813044 Thursday 12:15 PM 1:15 PM
Albertville 4019 860 Country Club Road Albertville AL 35951 34.296807 -86.198587 Tuesday 12:00 PM 1:00 PM
Alexander City 29375 16 Broad St. Alexander City AL 35010 32.945387 -85.953948 Monday 12:00 PM 1:00 PM
The "Clubs" Class is shown below.
public Club(string name, ClubTypes type, long idNumber, RecurrableMeeting regularMeeting = null, RecurrableMeeting boardMeeting = null, List<IndividualMeeting> otherMeetings = null)
{
this.name = name;
this.type = type;
this.idNumber = idNumber;
this.regularMeeting = regularMeeting;
this.boardMeeting = boardMeeting;
this.otherMeetings = otherMeetings;
if (this.otherMeetings == null)
this.otherMeetings = new List<IndividualMeeting>();
}
"The line "outcome.Add(text); " shows an error as I am trying to send the wrong type to the list."
The reason for this error is that you're trying to add a string[] to a list that contains Club. What we need is a method that will take a string and return a Club, and then we can call that method on each file line before adding to the list.
A common way to do this is to add a Parse method to the Club class that can create an instance of the class from a string.
A complete example could be provided if you shared some sample lines from the text file (typically these would map to properties of the class) and the definition of the Club class. However, here is a sample that you can hopefully apply to your specific situation.
First, example lines in a text file:
1,Ravens,10/10/2019,2
2,Lions,05/25/2019,5.7
3,Tigers,09/12/2018,6.2
4,Bears,11/05/2019,9.1
5,Wildcats,03/04/2017,4.8
And the definition of Club
public class Club
{
public int Id {get; set;}
public string Name {get; set;}
public DateTime FoundedOn {get; set;}
public double Score {get; set;}
}
As you can see, the lines in the text file map to properties of the Club class. Now we just need to add a static method to the Club class that returns an instance of the class based on a line of text from the file.
The idea is that we split the line on the comma character, convert each part to the correct data type for the property, set the properties, and return the class. We need to validate things like:
The line is not null
The line contains the correct number of parts
Each part is the correct datatype
In the case of a validation failure, we have some common choices:
Throw an exception
Return null
Return a partially populated class
In the sample below I'm returning null to indicate bad data, mostly because it makes parsing the file easier.
Here's the class with the Parse method added:
public class Club
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime FoundedOn { get; set; }
public double Score { get; set; }
public static Club Parse(string input)
{
// Try to split the string on the comma and
// validate the result is not null and has 4 parts
var parts = input?.Split(',');
if (parts?.Length != 4) return null;
// Strongly typed variables to hold parsed values
int id;
string name = parts[1].Trim();
DateTime founded;
double score;
// Validate the parts of the string
if (!int.TryParse(parts[0], out id)) return null;
if (name.Length == 0) return null;
if (!DateTime.TryParse(parts[2], out founded)) return null;
if (!double.TryParse(parts[3], out score)) return null;
// Everything is ok, so return a Club instance with properties set
return new Club {Id = id, Name = name, FoundedOn = founded, Score = score};
}
}
Now that we have the parse method, we can create a List<Club> from the text file quite easily:
public static List<Club> ReadClubsTxtFile(string path)
{
return File.ReadAllLines(path).Select(Club.Parse).ToList();
}
You could do something like this:
string path = "C:\\Users\\Clubs-2019";
public List<Club> ReadClubsTxtFile()
{
return File.ReadAllLines(path)
.Select( line => new Club {SomeProperty = line} )
.ToList();
}

How to convert object into json array without property names

For this class
class Customer {
public string FirstName {get; set;}
public string LastName {get; set;}
}
I have collection
List<Customer> customers
When returning to browser client
return new JsonResult(new
{
data = customers
});
The client get
{"data":[{"firstName":"Johny","lastName":"Johnson"}]}
Is there some way to get
{"data":[{"Johny","Johnson"}]}
without doing foreach like
var output = new List<string[]>();
foreach (var r in customers)
{
output.Add(new string[] {
r.FirstName,
r.LastName
});
}
?
You could add another property in the Customer object,
public string[] FullName {get { return new string[]{FirstName, LastName}; } }
Decorate your Firstname and LastName properties with [JsonIgnore] so they don't get serialized.
Final product would look like so
public class Customer{
[JsonIgnore]
public string FirstName{get;set;}
[JsonIgnore]
public string LastName{get;set;}
[JsonProperty("data")]
public string[] FullName {get { return new string[]{FirstName, LastName}; } }
public Customer(string FirstName, string LastName){
this.FirstName = FirstName;
this.LastName = LastName;
}
}
public static void Main(string[] args)
{
Customer c = new Customer("Adrian", "i6");
Console.Write(JsonConvert.SerializeObject(c));
}
This of course won't return exactly the desired result, if you wanted to completely remove the property you'll have to override the JsonWrite method inside JsonConverter however that would cause the JSON to be invalid of course as the JSON object requires a key:value property.
DotNetFiddle runnable of the above.
If you want some sort of "automatically derive a table from an array of JSON objects" functionality that's general across any data type, the algorithm would be to:
Iterate over the array, collecting newly-encountered property names into a list as you go into column names. This is the only way to get all property names since it may not be guaranteed that all objects have the same properties in JSON.
Create a list for each object in the list
Map each object's property value into the list index of the column corresponding to the property name
This will give you two output artifacts: the column listings and the values by index. If you are safe assuming that the first object has the same properties as all the other objects in the Array, then you can avoid iterating over the entire collection for the first step. This is untested, but hopefully you get the gist.
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
// ...
var payload = JObject.Parse(rawJson);
var dataArray = payload["data"] as JArray;
var firstItem = dataArray[0] as JObject;
var columns = firstItem.Properties().Select(prop => prop.Name).ToList();
var rows = (
from obj as JObject in dataArray
select columns.Select(col => obj[col]).ToList()
).ToList();

Cannot access a variable due to the access level protection

I have following classes:
class Department
{
private string departmentId;
private string departmentName;
private Hashtable doctors = new Hashtable();//Store doctors for
//each department
public Hashtable Doctor
{
get { return doctors; }
}
}
I have an array list that holds department objects:
private static ArrayList deptList = new ArrayList();
public ArrayList Dept
{
get { return deptList; }
}
I am trying to get all the doctors(the Hashtable in department class) from each department:
foreach (Department department in deptList)
{
foreach (DictionaryEntry docDic in department.Doctor)
{
foreach (Doctor doc in docDic.Value)//this is where I gets an error
{
if (doc.ID.Equals(docID))//find the doctor specified
{
}
}
}
}
But I can not compile the program. It gives an Error:
foreach statement cannot operate on variables of type 'object' because
'object' does not contain a public definition for 'GetEnumerator'
You are trying to iterate through a dictionary entry's Value field treating it as if it was a collection of Doctors. The iteration for docDic should already do what you are looking for, just need to cast the appropriate field (probably Value) of the docDic DictionaryEntry.
Doctor doc = (Doctor) docDic.Value;
Better yet, you could use generics and denote the types of the dictionary key/value at declaration of the map:
private Hashtable<string, Doctor> doctors = new Hashtable<string, Doctor>();
(similar change for the Doctor field)
Then you don't need the casting above at all.
Note: I assumed you are mapping from a doctor's id (key) to the Doctor objects (value), and that the id is a string
Prefix your class with a Public access modifier
public class Department
{
private string departmentId;
private string departmentName;
private Hashtable doctors = new Hashtable();//Store doctors for
//each department
public Hashtable Doctor
{
get { return doctors; }
}
}

LINQ - Help me grasp it with an example I think LINQ should be able to solve!

I am trying to get into LINQ to objects as I can see the power of it. Lucky enough I have a question that I think LINQ should be able to solve.
Here is the question (the details are an example);
public class SchoolClass
{
public int ID;
public string Name;
public string Teacher;
public string RoomName;
public string Student_Name;
public int Student_Age;
}
As you can see by the example, there is a one to many relationship between the ClassName, Teacher and Room and the Students, i.e. there are potentially many students in the one class.
If we have a List is it possible using LINQ to create a List but have only one instance ID, Name, Teacher, RoomName and an ArrayList of Student_Name and Age?
Producing this:
public class Students
{
public string Student_Name;
public int Student_Age;
}
public class SchoolClass
{
public int ID;
public string Name;
public string Teacher;
public string RoomName;
public ArrayList Students;
}
Essentially, using LINQ to clean the List to a more logical structure?
To give some background to this example. The second structure is used by a DataGrid to produce a Master-Child relationship. We store SchoolClass and StudentInformation in classes as shown above. It would be good use of LINQ to be able to convert our initial List into a structure which can be used by the DataGrid.
I changed the ArrayList to List<Students>, and:
List<SourceData> source = new List<SourceData>();
//...your data here ;-p
var classes = (from row in source
group row by new {
row.ID, row.Name,
row.Teacher, row.RoomName }
into grp
select new SchoolClass
{
ID = grp.Key.ID,
Name = grp.Key.Name,
Teacher = grp.Key.Teacher,
RoomName = grp.Key.RoomName,
Students = new List<Students>(
from row in grp
select new Students
{
Student_Age = row.Student_Age,
Student_Name = row.Student_Name
})
}).ToList();
If I'm understanding this correctly, I would've thought the best way to implement the SchoolClass class would be to create a Student class (probably a LINQ-to-SQL entity, if you're using it) and to have a generic list of type student, something similar to this:
public class SchoolClass
{
public int ID;
public string Name;
public string Teacher;
public string RoomName;
public List<Student> Students;
}
The list of students could then be populated using a linq query, although I'm not sure exactly how without more information.
Hope this is some help.

Categories