I'm reading a CSV file
Name,Score
Pat,99%
Chris,87%
and would like to discard the percent sign when the file is read through FileHelpers
using FileHelpers;
public class PctConverter : ConverterBase
{
private NumberFormatInfo nfi = new NumberFormatInfo();
public PctConverter()
{
nfi.PercentSymbol = "%";
}
public override object StringToField(string from)
{
return decimal.Parse(from, NumberStyles.Percent, nfi);
}
}
[DelimitedRecord(",")]
[IgnoreFirst]
public class Student
{
public string Name { get; set; }
public decimal Score { get; set; }
}
var student_file = "students.csv";
var engine = new FileHelperEngine<Student>();
engine.ErrorManager.ErrorMode = ErrorMode.SaveAndContinue;
List<Student> students = engine.ReadFileAsList(student_file);
ErrorInfo[] readingErrors = engine.ErrorManager.Errors;
But my converter is not quite right. Can you suggest why?
You need to specify the converter on the field you want converted, also your converter didn't work for me so I simplified it a bit:
public class PctConverter : ConverterBase
{
public override object StringToField(string from)
{
return decimal.Parse(from.Replace("%", ""));
}
}
[DelimitedRecord(",")]
[IgnoreFirst]
public class Student
{
public string Name { get; set; }
[FieldConverter(typeof(PctConverter))]
public decimal Score { get; set; }
}
Related
when im trying to desrialize to abstract class list,The Genres property in Book class stay Null, While in Journal class its get the value from my json file.
string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
using (FileStream streamFile = File.Open($"{folderPath}//products10.json", FileMode.OpenOrCreate))
{
using (StreamReader reader = new StreamReader(streamFile))
{
string fileContent = reader.ReadToEnd();
productsList = JsonConvert.DeserializeObject<List<ProductBase>>(fileContent,ProductBase.StrandartJsonConvert);
}
}
This is the JSON file:
[
{
"EditorName":"Me",
"Name":"DailyMail",
"IssueNumber":4,
"Genres":[1],
"Frequency":0,
"Id":"01c26581-3e3a-4bc2-bc97-dfbab0215f29",
"Description":"DailyMail",
"PublicationDate":"2022-01-19T12:44:32.57574+02:00",
"BasePrice":15.0,
"Type":"Journal"
},
{
"AuthorName":"Author",
"Title":"HarryPotter",
"Edition":3,
"Geners":[2,1],
"Synopsis":null,
"Id":"6674b82d-6d6d-49ac-9c92-7d84b0dd09b6",
"Description":"HarryPotter",
"PublicationDate":"2022-01-19T12:44:30.2413124+02:00",
"BasePrice":35.0,
"Type":"Book"
}
]
While in my journal class everything get in, in my book class - it isn't, it looks like the deserializtion ignores the Genres property.
public class Journal : ProductBase
{
public string EditorName { get; set; }
public string Name
{
get { return base.Description; }
set { base.Description = value; }
}
public int IssueNumber { get; set; }
public ICollection<JournalGenre> Genres { get; set; }
public JournalFrequency Frequency { get; set; }
public Journal(string editorName, string name, int issueNumber, DateTime publicationDate,
decimal basePrice, JournalFrequency frequency, params JournalGenre[] genres)
: base(name, publicationDate, basePrice)
{
this.EditorName = editorName;
this.IssueNumber = issueNumber;
this.Frequency = frequency;
this.Genres = genres.ToList();
}
}
here all the properties get the values.
public class Book : ProductBase
{
public string AuthorName { get; set; }
public string Title
{
get { return base.Description; }
set { base.Description = value; }
}
public int Edition { get; set; }
public ICollection<BookGenre> Geners { get; set; }
public string Synopsis { get; set; }
public Book(string authorName, string title, DateTime publicationDate, decimal basePrice, int edition = 1, params BookGenre[] genres)
:base(title, publicationDate, basePrice)
{
this.AuthorName = authorName;
this.Edition = edition;
this.Geners = genres.ToList();
}
}
but here the Genres stays null - the 'genres' in the const isnt get the value from the JSON file - only this prop. anything else get value.
Not sure why #JamesS deleted his answer, but he's right - the property in the JSON file is Geners for your Book, but the constructor parameter is genres.
Either correct the spelling of the property on the class and in the JSON file to Genres:
public class Book : ProductBase
{
...
public ICollection<BookGenre> Genres { get; set; }
{
"AuthorName":"Author",
"Title":"HarryPotter",
"Edition":3,
"Genres":[2,1],
"Synopsis":null,
"Id":"6674b82d-6d6d-49ac-9c92-7d84b0dd09b6",
"Description":"HarryPotter",
"PublicationDate":"2022-01-19T12:44:30.2413124+02:00",
"BasePrice":35.0,
"Type":"Book"
}
Or change the spelling of the constructor parameter to match the name used in the JSON file:
public Book(
string authorName,
string title,
DateTime publicationDate,
decimal basePrice,
int edition = 1,
params BookGenre[] geners)
I have 3 model types:
public class BankA_Transaction : BanKTransactionMetaData
{
public string GROUPName { get; set; }
public string ACC_ID { get; set; }
public string ACCOUNT_NO { get; set; }
}
public class BankB_Transaction : BanKTransactionMetaData
{
public string Name { get; set; }
public string ACC_ID { get; set; }
public string ACCOUNT_NO { get; set; }
}
public class BankC_Transaction : BanKTransactionMetaData
{
public string FullName { get; set; }
public string ACC_ID { get; set; }
public string ACCOUNT_NO { get; set; }
}
Note: The actual property lists are much longer
All of which inherit some fields needed when saving into the database.
public class BanKTransactionMetaData
{
public String BankName { get; set; }
}
These models get filled with records from a file sent by the bank and then saved to a database.
As part of this save I convert the records to JSON as that is required by the database.
public void SaveBankA(BankA bankA)
{
bankA.BankName = "Bank_A";
string jsonText = JsonConvert.SerializeObject(bankA_Transaction, Formatting.Indented);
Code for saving...
At the moment I have a different methods for SaveBankA, SaveBankA and SaveBankB.
It seems to me that this is code replication and that I should get all the models to inherit better in order to use a base type? instead of each named type.
I've read up on Abstract and Virtual classes as I suspect that's what I need but I can't work out how to plug it together.
I can't just use Object in SaveBankA as I need to add .BankName.
Is there a better architecture to reduce code replication?
Perhaps you need something like this?
In base service class:
protected void SaveBankTransaction(BankTransactionMetaData tran)
{
string jsonText = JsonConvert.SerializeObject(tran, Formatting.Indented);
// additional saving code
}
In child service classes:
public void SaveBankA(BankA bankA)
{
bankA.BankName = "Bank_A";
base.SaveBankTransaction(bankA);
}
Create a couple of interfaces, one for your meta data (IBankData) and one for your bank transaction details (IBankTransaction). The IBankData interface will maintain a reference to the IBankTransaction interface. This should also allow you to add additional banks when needed, e.g. Bank D.
public interface IBankData
{
string BankName { get; }
// ... additional bank meta data properties
// ...
IBankTransaction Transaction { get; set; }
}
public interface IBankTransaction
{
[JsonProperty("ACC_ID")]
string AccountId { get; set; }
[JsonProperty("ACCOUNT_NO")]
string AccountNumber { get; set; }
// ... additional shared bank transaction properties
// ...
}
FYI, I chose to use the JsonProperty attribute to control the name for the JSON key, this allows the class properties to be named according to best practices without affecting the JSON property names.
Next implement the interfaces for each bank you will be working with. In each bank add the additional properties that will only apply to each implementation, i.e. since the GroupName property is only used by BankA, this property will be added to the BankA class and not the interface. The same goes for any other bank specific properties.
Bank A
public class BankA : IBankData
{
public string BankName => "BankA";
public IBankTransaction Transaction { get; set; }
}
public class BankATransaction : IBankTransaction
{
// Bank A specific properties
[JsonProperty("GROUPName")]
public string GroupName { get; set; }
// ... additional Bank A specific properties
// ...
// interface implemented properties
public string AccountId { get; set; }
public string AccountNumber { get; set; }
}
Bank B
public class BankB : IBankData
{
public string BankName => "BankB";
public IBankTransaction Transaction { get; set; }
}
public class BankBTransaction : IBankTransaction
{
// Bank B specific properties
public string Name { get; set; }
// ... additional Bank B specific properties
// ...
// interface implemented properties
public string AccountId { get; set; }
public string AccountNumber { get; set; }
}
Bank C
public class BankC : IBankData
{
public string BankName => "BankC";
public IBankTransaction Transaction { get; set; }
}
public class BankCTransaction : IBankTransaction
{
// Bank B specific properties
public string FullName { get; set; }
// ... additional Bank B specific properties
// ...
// interface implemented properties
public string AccountId { get; set; }
public string AccountNumber { get; set; }
}
JsonConverter
Since the IBankTransaction is a property within the IBankData this will change your JSON structer. You may not want this, to retain your structure, a JsonConverter can be implemented on the IBankData interface. This will remove the Transaction object in the JSON and move the child properties under the JSON root.
public class BankJsonConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JToken t = JToken.FromObject(value);
if (t.Type != JTokenType.Object)
{
t.WriteTo(writer);
}
else
{
JObject o = (JObject)t;
JProperty transactionProperty = o.Properties().FirstOrDefault(p => p.Name == "Transaction");
o.Remove("Transaction");
JToken token = transactionProperty;
foreach (JToken ct in token.Children())
{
foreach (var prop in JProperty.FromObject(ct))
{
o.Add(prop);
}
}
serializer.Serialize(writer, o);
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
}
public override bool CanRead => false;
public override bool CanConvert(Type objectType)
{
return objectType.GetInterfaces().Contains(typeof(IBankData));
}
}
Usage
For the usage example I've created a few test functions to prep the data and added SaveBank method that you can relocate in your actual code as it would make sense for your solution.
class Program
{
static void Main(string[] args)
{
string bankATransJson = GetBankATestJsonInput();
BankATransaction bankATransaction = JsonConvert.DeserializeObject<BankATransaction>(bankATransJson);
BankA bankA = new BankA();
bankA.Transaction = bankATransaction;
Console.WriteLine(SaveBank(bankA));
// output:
// {
// "BankName": "BankA",
// "GROUPName": "g54321",
// "ACC_ID": "A01",
// "ACCOUNT_NO": "A1111"
// }
string bankBInputJson = GetBankBTestJsonInput();
BankBTransaction bankBTransInput = JsonConvert.DeserializeObject<BankBTransaction>(bankBInputJson);
BankB bankB = new BankB();
bankB.Transaction = bankBTransInput;
Console.WriteLine(SaveBank(bankB));
// output:
// {
// "BankName": "BankB",
// "ACC_ID": "B02",
// "ACCOUNT_NO": "B2222",
// "Name": "Bank_Of_B
// }
string bankCInputJson = GetBankCTestJsonInput();
BankCTransaction bankCTransInput = JsonConvert.DeserializeObject<BankCTransaction>(bankCInputJson);
BankC bankC = new BankC();
bankC.Transaction = bankCTransInput;
Console.WriteLine(SaveBank(bankC));
// output:
// {
// "BankName": "BankC",
// "ACC_ID": "C03",
// "ACCOUNT_NO": "C3333",
// "FullName": "C Bank"
// }
}
public static string SaveBank(IBankData bankData)
{
// when calling the serialize object method, we pass our BankJsonConverter
string jsonText = JsonConvert.SerializeObject(bankData, Formatting.Indented, new BankJsonConverter());
// this example just returns the JSON text
// but you would implement your save logic as needed
return jsonText;
}
private static string GetBankATestJsonInput()
{
var obj = new { ACC_ID = "A01", ACCOUNT_NO = "A1111", GROUPName = "g54321" };
return JsonConvert.SerializeObject(obj);
}
private static string GetBankBTestJsonInput()
{
var obj = new { ACC_ID = "B02", ACCOUNT_NO = "B2222", Name = "Bank_Of_B" };
return JsonConvert.SerializeObject(obj);
}
private static string GetBankCTestJsonInput()
{
var obj = new { ACC_ID = "C03", ACCOUNT_NO = "C3333", FullName = "C Bank" };
return JsonConvert.SerializeObject(obj);
}
}
How can I access the custom attribute of the parent or owner object.
Look at the FieldInfo property of the SQLFieldInfo struct
Here's a more detailed program that will compile and run that shows what I need.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Employee myclass = new Employee();
// Load from sql server...
myclass.Name = "Alain";
myclass.Age = 51;
//----
MessageBox.Show(myclass.Name.ToString()); // Should return Alain
MessageBox.Show(myclass.Age.FieldInfo.Type.ToString()); // Should output "int"
}
}
// This next class is generated by a helper exe that reads SQL table design and create the class from it
[SQLTableAttribute(DatabaseName = "Employees", Schema = "dbo", TableName = "Employees")]
public class Employee
{
[SQLFieldAttribute(FieldName = "ID", Type = SqlDbType.Int)]
public SQLFieldInfo<int> ID { get; set; }
[SQLFieldAttribute(FieldName = "Name", Type = SqlDbType.NVarChar, Size = 200)]
public SQLFieldInfo<String> Name { get; set; }
[SQLFieldAttribute(FieldName = "Age", Type = SqlDbType.Int)]
public SQLFieldInfo<int> Age { get; set; }
}
public struct SQLFieldInfo<T>
{
private readonly T value;
public SQLFieldInfo(T Value)
{
this.value = Value;
}
public static implicit operator SQLFieldInfo<T>(T Value)
{
return new SQLFieldInfo<T>(Value);
}
public T Value
{
get
{
return this.value;
}
}
public override string ToString()
{
return this.value.ToString();
}
public SQLFieldAttribute FieldInfo
{
get
{
// Need to retreive the attribute class of the parent or declaring member
return null;
}
}
}
// Holds the sql field information
public class SQLFieldAttribute : Attribute
{
public string FieldName { get; set; }
public SqlDbType Type { get; set; }
public bool AllowNull { get; set; }
public int Size { get; set; }
}
// Holds the sql table information
public class SQLTableAttribute : Attribute
{
public string DatabaseName { get; set; }
public string Schema { get; set; } = "dbo";
public string TableName { get; set; }
}
Thank you!
Alain
My data class is as follows (should be fairly translatable to A above):
public class Foo
{
[Argument(Help = "Name", AssignmentDelimiter = "=")]
public string Name
{
get;
set;
}
}
A helper class is responsible of reading attribute values of objects:
static public string GetCommandLineDelimiter<T>(Expression<Func<T>> property)
{
if(property != null)
{
var memberExpression = (MemberExpression)property.Body;
string propertyName = memberExpression.Member.Name;
PropertyInfo prop = typeof(Arguments).GetProperty(propertyName);
if(prop != null)
{
object[] dbFieldAtts = prop.GetCustomAttributes(typeof(ArgumentAttribute), true);
if(dbFieldAtts.Length > 0)
{
return ((ArgumentAttribute)dbFieldAtts[0]).AssignmentDelimiter;
}
}
}
return null;
}
To use it, simply:
string delimiter = GetCommandLineDelimiter(() => myObject.Name);
That will get the attribute value of AssignmentDelimiter on property Name, i.e. "=".
First, MSDN is your friend.
Then, if you want to get the attributes for ancestors just specify true in the inherit flag of the method:
var attribute = typeof(A).GetProperty("myprop").GetCustomAttributes(true)
.OfType<MycustomAttrib>().FirstOrDefault();
This works. I am doing a lazy initialization of a reference to the custom attribute by using reflection to look at all the properties of all the types.
public class MycustomAttribAttribute : Attribute
{
public MycustomAttribAttribute(string name)
{
this.Name=name;
}
public string Name { get; private set; }
}
class A
{
public A() { MyProp=new B(); }
[MycustomAttrib(name: "OK")]
public B MyProp { get; set; }
}
class B
{
private static Lazy<MycustomAttribAttribute> att = new Lazy<MycustomAttribAttribute>(() =>
{
var types = System.Reflection.Assembly.GetExecutingAssembly().DefinedTypes;
foreach(var item in types)
{
foreach(var prop in item.DeclaredProperties)
{
var attr = prop.GetCustomAttributes(typeof(MycustomAttribAttribute), false);
if(attr.Length>0)
{
return attr[0] as MycustomAttribAttribute;
}
}
}
return null;
});
public string MyProp2
{
get
{
return att.Value.Name;
}
}
}
class Program
{
static void Main(string[] args)
{
// Finds the attribute reference and returns "OK"
string name = (new A()).MyProp.MyProp2;
// Uses the stored attribute reference to return "OK"
string name2 = (new A()).MyProp.MyProp2;
}
}
Trying to get the result from a webservice call to return a Model. I eep getting the error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'CI.Models.Schedule' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
public Schedule getCourseSchedule()
{
var obj = new
{
States = new[] { new { State = "MX" } },
Zip = "",
Miles = "",
PaginationStart = 1,
PaginationLimit = 3
};
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "apoplication/json";
var url = "http://192.168.1.198:15014/ShoppingCart2/CourseSchedule";
var json = JsonConvert.SerializeObject(obj);
byte[] data = Encoding.UTF8.GetBytes(json);
byte[] result = client.UploadData(url, data);
string returnjson = Encoding.UTF8.GetString(result);
Schedule sched = JsonConvert.DeserializeObject<Schedule>(returnjson);
return sched;
}
}
Schedule Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Globalization;
namespace CI.Models
{
public class Schedule
{
public IEnumerable<Course> Courses { get; set; }
}
public class Course
{
/*
JSON Data returned from web service:
{
"ProgramGroup":"MR",
"ProgramCode":"RM",
"EventCode":"20160901MXMR",
"FormalDate":"September 1-2, 2016",
"StartDate":"2016\/09\/01",
"Price":5,
"LocName":"WB Hotel",
"LocAddress":"Av. Speedy Gonzales 220",
"LocCity":"Monterrey",
"LocState":"MX",
"LocZipCode":null,
"LicenseeURL":null,
"AgendaURL":"NA",
"SeatsAreAvailable":"2",
"GeneralInfoHTML":"General Info goes here.",
"GateKeeperHTML":null,
"EventType":"SS",
"TotalCourses":3
}
*/
public string ProgramGroup { get; set; }
public string ProgramCode { get; set; }
public string EventCode { get; set; }
public string FormalDate { get { return FormalDate; } set { FormalDate = convertFormalDateToSpanish(value); } }
public string StartDate { get; set; }
public double Price { get; set; }
public string LocName { get; set; }
public string LocAddress { get; set; }
public string LocCity { get ; set; }
public string LocState { get; set; }
public string LocZipCode { get; set; }
public string LicenseeURL { get; set; }
public string AgendaURL { get { return AgendaURL; } set { AgendaURL = buildAgendaLink(value); } }
public string SeatsAreAvailable { get; set; }
public string GeneralInfoHTML { get; set; }
public string GateKeeperHTML { get; set; }
public string EventType { get; set; }
public int TotalCourses { get; set; }
public string convertFormalDateToSpanish(string val)
{
DateTime TheDate = DateTime.Parse(StartDate);
string[] FormalDate = val.Split(" ".ToCharArray());
CultureInfo ci = new CultureInfo("es-ES");
string _Date = FormalDate[1].Replace("-", " al ").Replace(",", "");
string _Month = ci.TextInfo.ToTitleCase(TheDate.ToString("MMMM", ci));
val = string.Concat(_Date, " ", _Month);
return val;
}
private string buildAgendaLink(string val)
{
if (val.Trim() != "")
{
val = string.Concat("Agenda");
}
else
{
val = "Agenda";
}
return val;
}
}
}
Your server returns an array. Just try
Course[] courses = JsonConvert.DeserializeObject<Course[]>(returnjson);
Note that this is not an answer to your original problem, but I added it like an answer in order to explain my comment above with some actual code.
First problem with your code is that FormalDate and AgendaUrl properties simply won't work. Accessing them will result in a StackOverflowException, because you basically defined them recursively.
A property is merely syntax sugar for two separate getter/setter methods, so by writing this:
public class Course
{
public string FormalDate
{
get { return FormalDate; }
}
}
You are basically writing this:
public class Course
{
public string GetFormalDate()
{
// recursive call, with no terminating condition,
// will infinitely call itself until there is no
// more stack to store context data (and CLR
// will then throw an exception)
return GetFormalDate();
}
}
To fix that, you need to add an actual backing field, e.g.:
public class Course
{
private string _formalDate; // <-- this is a backing field;
// and this property uses the backing field to read/store data
public string FormalDate
{
get { return _formalDate; }
set { _formalDate = convertFormalDateToSpanish(value); }
}
}
Additionally, it's unusual for a property getter to return a different value than the one set through a setter. In other words, I would never expect this from a class:
var course = new Course();
course.StartDate = "2016/09/01";
course.FormalDate = "September 1-2, 2016";
Console.WriteLine(course.FormalDate); // prints "1 al 2 Septiembre" ?
I would rather move this functionality into a different class, or at least create different properties which return these values:
public class CourseInfo
{
// this is now a "dumb" auto-implemented property
// (no need for a backing field anymore)
public string FormalDate { get; set; }
// this read-only property returns the converted value
public string LocalizedFormalDate
{
get
{
return convertFormalDateToSpanish(FormalDate);
}
}
}
i am working on a small app that mange flights, i have a class that build a flight details and class that build the passenger, now, i want to load the passengers onto a flight, how should i do it? do i need to build a higer class that inherit from this two class and make a list of that type of class(i dont think that wise oop ).or should i add a ticket prop in the passenger class that have the flight number, here is my code.
public class Passenger
{
public Passenger(string name, int passportNumber)
{
this.PassengerName = name;
this.PassportNumber = passportNumber;
}
private string _passengerName;
public string PassengerName
{
get { return _passengerName; }
set { _passengerName = value; }
}
private int _passportNumber;
public int PassportNumber
{
get { return _passportNumber; }
set { _passportNumber = value; }
}
}
public class FlightDetails
{
public FlightDetails(int flightNumber, string flightDestination, string planmodel)
{
this.FlightNumber = flightNumber;
this.FlightDestination = flightDestination;
this.PlanModel = planmodel;
}
private int _flightNumber;
public int FlightNumber
{
get { return _flightNumber; }
set { _flightNumber = value; }
}
private string _flightDestination;
public string FlightDestination
{
get { return _flightDestination; }
set { _flightDestination = value; }
}
private string _planeModel;
public string PlanModel
{
get { return _planeModel; }
set { _planeModel = value; }
}
}
static void Main(string[] args)
{
List<FlightDetails> flightList = new List<FlightDetails>();
FlightDetails a = new FlightDetails(12,"france","jumbo");///create a flight
flightList.Add(a);/// load up the flight
}
First, you can't create a class that inherits from both other classes because multiply inheritance is not allowed in C#.
You can use aggregation, something like this:
public class FlightDetails
{
// ...
}
public class Passenger
{
// ...
}
public class Flight
{
public FlightDetails { get; private set; }
public List<Passenger> Passengers { get; private set; }
public Flight(FlightDetails details)
{
FlightDetails = details;
Passengers = new List<Passenger>();
}
public AddPassenger(Passenger p)
{
// check for ticket and so on..
Passengers.Add(p);
}
}
You can read more about aggregation here: http://en.wikipedia.org/wiki/Object_composition#Aggregation
Note that in this example for simplicity i used List but actually you need to limit access to this array (because otherwise i can do something like this: Flight.Passengers.Add(p) instead of Flight.AddPassenger(p)) so good idea will be use ReadOnlyCollection as public interface to this list.
Here's a sample code that might work. A flight has one or more passengers, thus has a List of type Passenger. In real-life, a passenger can book multiple flights. If you want the reality, you'll have to change your model but for this situation it'll work:
public class Passenger
{
public Passenger(string name, int passportNumber)
{
PassengerName = name;
PassportNumber = passportNumber
}
public string PassengerName { get; set; }
public int PassportNumber { get; set; }
}
public class FlightDetails
{
public FlightDetails(int flightNumber, string flightDestination, string planmodel)
{
FlightNumber = flightNumber;
FlightDestination = flightDestination;
PlanModel = planmodel;
Passengers = new List<Passengers>();
}
public int FlightNumber { get; set; }
public string FlightDestination { get; set; }
public string PlanModel { get; set; }
public List<Passenger> Passengers { get; private set; }
public void AddPassenger(string name, int number)
{
int max = 2;
int passengersNumber = Passengers.Count;
if (passengersNumber < max)
{
Passengers.Add(new Passenger(name, number);
}
}
public static void Main(string[] args)
{
var flightList = new List<FlightDetails>();
var passengersList = new List<Passenger>();
//Add passenger-objects to passengers-list
var flightOne = new FlightDetails(12, "France", "Jumbo");
flightOne.Passengers = passengersList;
flightList.Add(a);
}
Here's a better solution to limit the passengers:
public class FlightDetails
{
public FlightDetails(int flightNumber, string flightDestination, string planmodel)
: this(flightNumber, flightDestination, planmodel, new List<Passenger>())
{
}
public FlightDetails(int flightNumber, string flightDestination, string planmodel, List<Passenger> passengers)
{
FlightNumber = flightNumber;
FlightDestination = flightDestination;
PlanModel = planmodel;
if(passengers.Count > 2)
//throw exception or error
else
_passengers = passengers;
}
private List<Passenger> _passengers = new List<Passenger>();
public int FlightNumber { get; set; }
public string FlightDestination { get; set; }
public string PlanModel { get; set; }
public IEnumerable<Passenger> Passengers { get { return _passengers; } }
public void AddPassenger(string name, int number)
{
int max = 2;
int passengersNumber = _passengers.Count;
if (passengersNumber < max)
{
_passengers.Add(new Passenger(name, number);
}
}
}
Note: this code is written without compiling. But the idea is correct normally. :)
In logical way, relation between FlightDetail to Passenger is OneToMany. One FlightDetail can have multiple Passenger which is can be written as below. FlightDetail and Passenger should be have any common inheritance hierarchy because they are don't have any common attribute or behaviour.
public class FlightDetails
{
private List<Passenger> passengerList;
public void addPassenger(Passenger p){
if(passengerList == null){
passengerList = new ArrayList<Passenger>();
}
passengerList.add(p);
}
public List<Passenger> getPassengerList(){
return passengerList;
}
//... your other detail
}
You should add a FlightDetails property to your Passenger class. That's easier than making a List with PassportNumber as index. But, it's easier to iterate FlightDetails using List, than accessing it through Passenger.
It actually depends on how you want to access and store the relations.
It might be a good idea to read about the composite pattern which actually has a nice solution for travelling between parent-child relations, even though the pattern has another purpose.