Seed list inside an empty list - c#

I'm working with KnockoutMVC and it requires strongly type models to use inside the VIEW. I have tried multiple variations of the examples on KnockoutMVC's site including using ENUMS and still could not get it to work. Perhaps this is a problem with the setup of my models.
MODELS
public class PhoneNumber
{
public List<NumberTypeClass> Types { get; set; }
//public NumberType enumType { get; set; }
//public enum NumberType
//{
// Work,
// Home,
// Mobile,
// Fax
//}
private string _number;
[StringLength(14, MinimumLength = 10, ErrorMessage = "Please use (123) 456-7890 format"), Required]
public string Number
{
get
{
this._number = BeautifyPhoneNumber(this._number);
return this._number;
}
set
{
this._number = value;
}
}
public string Extension { get; set; }
public static String BeautifyPhoneNumber(string numberToBeautify)
{
//beautifyNumberCode
}
}
public class NumberTypeClass
{
public int Id { get; set; }
public string NumberType { get; set; }
}
public class VendorsEditorVendorModel
{
public string FirstName {Get;set;}
public string LastName {get;set;}
public List<Address> Address {get;set;}
public List<PhoneNumber> Phones {get;set;}
}
public class VendorsEditorModel
{
public List<VendorsEditorVendorModel> Vendors {get;set;}
}
CONTROLLER
public class VendorsEditorController : BaseController
{
public ActionResult CreateVendors()
{// VendorsEditor/CreateVendors
var vendor = new VendorsEditorModel();
vendor.Vendors = new List<VendorsEditorVendorModel>();
vendor.Vendors[0].Phones[0].Types = new List<NumberTypeClass>
{
new NumberTypeClass{Id = 0, TypeName = "Mobile"},
new NumberTypeClass{Id = 0, TypeName = "Work"},
new NumberTypeClass{Id = 0, TypeName = "Home"}
};//this throws an error because there is no Vendors[0] ...but how would i populate this list for every Vendor?
return View(vendor);
}
}

You cannot call an empty collection by index [x]. You need to fill your collection from a database or what not before you can access items in it. If you are just trying to add items to a collection, this is how you do it:
var vendor = new VendorsEditorModel
{
Vendors = new List<VendorsEditorVendorModel>
{
new VendorsEditorVendorModel
{
Phones = new List<PhoneNumber>
{
new PhoneNumber
{
Types = new List<NumberTypeClass>
{
new NumberTypeClass {Id = 0, NumberType = "Mobile"}
}
}
}
}
}
};
If you just want to add the types to an already populated collection, you can do the following:
foreach (var phone in vendor.Vendors.SelectMany(item => item.Phones))
{
phone.Types = new List<NumberTypeClass>
{
new NumberTypeClass{Id = 0, NumberType = "Mobile"},
new NumberTypeClass{Id = 0, NumberType = "Work"},
new NumberTypeClass{Id = 0, NumberType = "Home"}
};
}

Related

How can i get the name of property and value from object and pass this name and value to a list in c#

I want to get the property name and the value from object and pass them to the list.
i dont want to pass one by one property and value to the list like commented in my code. want to use loop and add name and value dynamically
public class ParametersList
{
public string Name { get; set; }
public dynamic Value { get; set; }
}
public class BookVM
{
public string AuthorName{ get; set; }
public string CoverUrl { get; set; }
public int AuthorIds { get; set; }
}
public List<Book> Addgetallbooks(BookVM BookVM)
{
List<ParametersList> obj = new List<ParametersList>();
//List<ParametersList> obj = new List<ParametersList>
//{
// new ParametersList{Name=nameof(BookVM.AuthorIds),Value=BookVM.AuthorIds},
// new ParametersList{Name=nameof(BookVM.AuthorName),Value=BookVM.AuthorName},
// new ParametersList{Name=nameof(BookVM.CoverUrl),Value=BookVM.CoverUrl}
//};
var getdata = _opr.GetBooks1(obj);
return getdata;
}
You need to use reflection, but not sure if you should do it :)
[TestMethod]
public void Foo()
{
var book = new BookVM() { AuthorIds = 1, AuthorName = "some name", CoverUrl = "some cover url" };
var result = GetParameters(book);
result.Should().BeEquivalentTo(new[]
{
new ParametersList { Name = nameof(BookVM.AuthorIds), Value = 1 },
new ParametersList() { Name = nameof(BookVM.AuthorName), Value = "some name" },
new ParametersList { Name = nameof(BookVM.CoverUrl), Value = "some cover url" }
});
}
private static List<ParametersList> GetParameters(BookVM book)
{
return typeof(BookVM).GetProperties().Select(p => new ParametersList
{
Name = p.Name, Value = p.GetValue(book)
}).ToList();
}

Something is getting wrong with adding a list to existing List

I'm trying to realize the listBox with List where i getting some variable.
And when i wonna to add a new "Object" to static List i getting a NullReferenceException
This is my code where i adding a new List
if (EventArgsIn.Message.Chat.Id == MainChatId)
{
if (EventArgsIn.Message.ReplyToMessage != null)
{
var _tempMessage = new listBoxMessage()
{
From = EventArgsIn.Message.From.Username,
FromId = EventArgsIn.Message.From.Id,
MessageId = EventArgsIn.Message.MessageId,
MessageText = EventArgsIn.Message.Text,
MessageIdReply = 0
};
tempMessageMain.Add(_tempMessage);
} else
{
var _tempMessage = new listBoxMessage() {
From = EventArgsIn.Message.From.Username,
FromId = EventArgsIn.Message.From.Id,
MessageId = EventArgsIn.Message.MessageId,
MessageText = EventArgsIn.Message.Text,
MessageIdReply = 0
};
tempMessageMain.Add(_tempMessage);
}
}
And here is my static List
public static List<listBoxMessage> tempMessageMain;
A-a-and my class where i doing Template
public class listBoxMessage
{
public listBoxMessage()
{
}
public string From { get; set; }
public int FromId { get; set; }
public int MessageId { get; set; }
public string MessageText { get; set; }
public int MessageIdReply { get; set; }
}
}
This is test code*
You declared a listbox with next line:
public static List<listBoxMessage> tempMessageMain;
The value of tempMessageMain is still null.
Now you have to create a new instance of tempMessageMain:
public static List<listBoxMessage> tempMessageMain = new List<listBoxMessage>();

Write an Observable Collection to Csv file

I have a datagridview that is bound to an observable collection in a mvvm fashion.
I'm trying to figure out how to write the collection to a csv file.
I can format the headers and get that put in, but not sure how one would iterate over a collection pulling out the values and putting them to a file with comma delimiting.
Here is my class
public class ResultsModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Phone { get; set; }
public string Username { get; set; }
public bool Sucess { get; set; }
public string MessageType { get; set; }
public string SenderMessageSent { get; set; }
public string SenderMessageReceived { get; set; }
}
which gets loaded into an observable collection
Here's a generic helper method which utilizes reflection to get values of all properties in the collection of objects and serializes to comma separated values string. (1 line = 1 object from collection)
public static IEnumerable<string> ToCsv<T>(IEnumerable<T> list)
{
var fields = typeof(T).GetFields();
var properties = typeof(T).GetProperties();
foreach (var #object in list)
{
yield return string.Join(",",
fields.Select(x => (x.GetValue(#object) ?? string.Empty).ToString())
.Concat(properties.Select(p => (p.GetValue(#object, null) ?? string.Empty).ToString()))
.ToArray());
}
}
And the examplary usage:
var oemResultsModels = new List<OemResultsModel>
{
new OemResultsModel
{
FirstName = "Fname1",
LastName = "LName1",
MessageType = "Type1",
Phone = 1234567,
SenderMessageReceived = "something1",
SenderMessageSent = "somethingelse1",
Sucess = true,
Username = "username1"
},
new OemResultsModel
{
FirstName = "Fname2",
LastName = "LName2",
MessageType = "Type2",
Phone = 123456789,
SenderMessageReceived = "something2",
SenderMessageSent = "somethingelse2",
Sucess = false,
Username = "username2"
}
};
using (var textWriter = File.CreateText(#"C:\destinationfile.csv"))
{
foreach (var line in ToCsv(oemResultsModels))
{
textWriter.WriteLine(line);
}
}

C# - Adding data to list inside list

How can I add the following data on the table into a list called Vehicles?
public class criterias
{
public double values { get; set; }
public double time { get; set; }
}
public class movChannels
{
public string name { get; set; }
public IList<criterias> criteria = new List<criterias>();
}
public class stepsList
{
public string steps { get; set; }
public IList<movChannels> stepChannelsCriteria = new List<movChannels>();
}
public class vehicles
{
public int vehID { get; set; }
public string vehDescription { get; set; }
public IList<stepsList> vehValCriteria = new List<stepsList>();
}
Now, how can I add the data that I have in the table shown into a list called Vehicles? I will create other vehicles later...
You had several bad decisions, some were design flaws and some were minor C# naming convention violations.
Couple of worth mentions flaws:
vehID should have been a string and not int (Example "XPT")
Movment has Name, Value and Time. It doesn't have a list of Values and Times.
Creation:
List<Vehicle> vehicles = new List<Vehicle>();
Vehicle vehicle = new Vehicle()
{
Id = "XPT",
Description = "Average Car",
Steps = new List<Step>()
{
new Step() {
Name = "move car",
Movements = new List<Movement>()
{
new Movement("engage 1st gear", 1, 1),
new Movement("reach 10kph", 10, 5),
new Movement("maintain 10kph", 10, 12),
}
},
new Step() {
Name = "stop car",
Movements = new List<Movement>()
{
new Movement("reach 0kph", 10, 4),
new Movement("put in neutral", 0, 1),
new Movement("turn off vehicle", 0, 0),
}
}
}
};
vehicles.Add(vehicle);
Entities:
public class Movement
{
public string Name { get; set; }
public double Values { get; private set; }
public double Time { get; private set; }
public Movement(string name, double values, double time)
{
Name = name;
Values = values;
Time = time;
}
}
public class Step
{
public string Name { get; set; }
public IList<Movement> Movements { get; set; }
}
public class Vehicle
{
public string Id { get; set; } // Should be changed to string
public string Description { get; set; }
public IList<Step> Steps { get; set; }
}
You should create your classes like the following:
public class criterias
{
public double values { get; set; }
public double time { get; set; }
}
public class movChannels
{
public movChannels
{
criteria = new List<criterias>();
}
public string name { get; set; }
public IList<criterias> criteria { get; set; }
}
public class stepsList
{
public stepsList
{
stepChannelsCriteria = new List<movChannels>();
}
public string steps { get; set; }
public IList<movChannels> stepChannelsCriteria { get; set; }
}
public class vehicles
{
public vehicles
{
vehValCriteria = new List<stepsList>();
}
public int vehID { get; set; }
public string vehDescription { get; set; }
public IList<stepsList> vehValCriteria { get; set; }
public movChannels movments { get; set; }
}
What about that?
public class VehiclesViewModel
{
public List<vehicles> Vehicles { get; private set; }
public void Initalize()
{
this.Vehicles = new List<vehicles>();
var vehicle = new vehicles
{
vehID = 1,
vehDescription = "firstDescription",
};
var stepsList = new stepsList
{
steps = "firstStep",
};
var movChannel = new movChannels
{
name = "firstChannel",
};
var criteria = new criterias
{
values = 0.5,
time = 0.5
};
movChannel.criteria.Add(criteria);
stepsList.stepChannelsCriteria.Add(movChannel);
vehicle.vehValCriteria.Add(stepsList);
this.Vehicles.Add(vehicle);
}
}
it seems in your table the VehicleId is of type string. Make sure your VehicleId property in Vehicle class also matches the same.
You can use the collection initializers to set the values of child objects like this way:
var data = new vehicles()
{
vehID = 1,
vehDescription = "Average Car",
vehValCriteria = new List<stepsList>()
{
new stepsList()
{
steps = "Move car",
stepChannelsCriteria = new List<movChannels>()
{
new movChannels()
{
name = "engage firstgear",
criteria = new List<criterias>()
{
new criterias()
{
values = 1,
time = 1
},
}
},
new movChannels()
{
name = "reach 10kph",
criteria = new List<criterias>()
{
new criterias()
{
values = 10,
time = 5
},
}
},
new movChannels()
{
name = "maintain 10kph",
criteria = new List<criterias>()
{
new criterias()
{
values = 10,
time = 12
},
}
}
}
},
new stepsList()
{
steps = "stop car",
stepChannelsCriteria = new List<movChannels>()
{
new movChannels()
{
name = "reach okph",
criteria = new List<criterias>()
{
new criterias()
{
values = 10,
time = 4
},
}
},
new movChannels()
{
name = "put in neutral",
criteria = new List<criterias>()
{
new criterias()
{
values = 0,
time = 1
},
}
},
new movChannels()
{
name = "turn off vehicle",
criteria = new List<criterias>()
{
new criterias()
{
values = 0,
time = 0
},
}
}
}
}
}
};
You can fill your list by moving from top to bottom, like
Create Criterias List then Create movChannel object and add that list
to Criterias object and so on
However if you want to avoid this way, there is another way. If you are using Linq To List then follow this
Get a simple flat object to a list object
var TableData = db.Tablename.Tolist();
Then fill your own object like this
Vehicles finalList = TableData.Select(a => new Vehicles()
{
vehID = a.Id,
vehDescription = a.des,
vehValCriteria = TableData.Where(b => b.StepslistId == a.StepslistId)
.Select(c => new StepsList()
{
steps = c.Steps,
stepChannelsCriteria = TableData.Where(d => d.channelId == c.channelId)
.select(e => new MovChannels()
{
name = e.name,
criteria = TableData.Where(f => f.criteriasId = e.criteriasId)
.Select(g => new Criterias()
{
values = g.Values,
time = g.Time
}).ToList()
}).ToList()
}).ToList()
}).ToList();
This is standard way to fill list within list

How to implement validation rules which are known only during runtime

I have the following situation.
I have a bunch of simple classes, for example this one
public class Student
{
public int Id { get; set; }
public int Age { get; set; }
public decimal AverageMark { get; set; }
public string Name { get; set; }
public string University { get; set; }
}
There is web page for every of them where user can create, edit and delete. When we create Student of update it, we need to validate it.
The problem is that we do not know validation rules during compilation !!!
We have separate web page for administrator where he set up validation criterias,
for example, that Student Age cannot be less then 15 or University have to be equal "SomeUniversity".
As result i have some list of criterias stored in my database
public class Criteria
{
public string PropertyName { get; set; }
public string OperationName { get; set; }
public string OperationValue { get; set; }
}
I have created simple console application for investigation purposes. Here is code
namespace DynamicValidation
{
class Program
{
static void Main(string[] args)
{
//set up students
var student1 = new Student() { Age = 20, AverageMark = 4, Name = "Ihor", University = "Lviv National University" };
var student2 = new Student() { Age = 20, AverageMark = 4, Name = "Taras", University = "Lviv National University" };
var student3 = new Student() { Age = 20, AverageMark = 5, Name = "Marko", University = "" };
var student4 = new Student() { Age = 20, AverageMark = 3, Name = "Tanya", University = "" };
var student5 = new Student() { Age = 22, AverageMark = 4, Name = "Ira", University = "" };
var students = new List<Student>() { student1, student2, student3, student4, student5 };
//set up validation rules
var criteria1 = new Criteria("Age", "Equal", "20");
var criteria2 = new Criteria("AverageMark", "NotLessThan", "4");
var criteria3 = new Criteria("University", "Contains", "Lviv");
var criterias = new List<Criteria>() { criteria1, criteria2, criteria3 };
var result = new List<Student>();
foreach (var currentStudent in students)
{
foreach (var currentCriteria in criterias)
{
object currentPropertyValue = typeof(Student).GetProperty(currentCriteria.PropertyName).GetValue(currentStudent);
//what is next ???!!!
}
}
}
}
public class Student
{
public int Id { get; set; }
public int Age { get; set; }
public decimal AverageMark { get; set; }
public string Name { get; set; }
public string University { get; set; }
}
public class Criteria
{
public string PropertyName { get; set; }
public string OperationName { get; set; }
public string OperationValue { get; set; }
}
}
How can i implement this piece of code ? (expression trees, dynamic ?)
I do not want that you do work for me but maybe there are some articles about this ? (i tried to found but without success)
Maybe some advices about approach ?
Maybe there is some similar open code ?
Or maybe it is already implemented in some libraries ?
Will be thankful for any help :)
You could write a student validator function, see IsValidStudent(Criteria criteria):
public class Student
{
public int Id { get; set; }
public int Age { get; set; }
public decimal AverageMark { get; set; }
public string Name { get; set; }
public string University { get; set; }
public bool IsValidStudent(Criteria criteria)
{
return IsValidByAge(criteria)
&& IsValidByMarks(criteria)
&& IsValidByUniversity(criteria);
}
private bool IsValidByAge(Criteria criteria)
{
switch (criteria.OperationType)
{
case Criteria.Operation.GreaterThan:
return Convert.ToInt32(criteria.OperationValue) > this.Age;
case Criteria.Operation.LessThan:
return Convert.ToInt32(criteria.OperationValue) < this.Age;
case Criteria.Operation.EqualTo:
return Convert.ToInt32(criteria.OperationValue) == this.Age;
default:
return false;
}
}
private bool IsValidByMarks(Criteria criteria)
{
// etc...
}
private bool IsValidByUniversity(Criteria criteria)
{
// etc...
}
}
Usage:
var result = new List<Student>();
foreach (var currentStudent in students)
{
foreach (var currentCriteria in criterias)
{
if (currentStudent.IsValidStudent(currentCriteria))
{
result.Add(currentStudent);
}
}
}
I also extended your Criteria class:
public class Criteria
{
public string PropertyName { get; set; }
public Operation OperationType { get; set; }
public string OperationValue { get; set; }
public enum Operation
{
EqualTo,
GreaterThan,
LessThan,
Contains
}
public Criteria(string propertyName, Operation operationType, string operationValue)
{
this.PropertyName = propertyName;
this.OperationType = operationType;
this.OperationValue = operationValue;
}
}
IMHO, I have found a little better solution then proposed
Now we do not need to change validation logic inside Student class if new property will be added. Also this code can be applied to any other class (not only for Student class as before)
Interface for validation
public interface IValidator
{
bool Validate(object value, object validateWith);
}
Set of implementations
public class ContainsValidator : IValidator
{
public bool Validate(object value, object validateWith)
{
string valueString = Convert.ToString(value);
string validateWithString = Convert.ToString(validateWith);
return valueString.Contains(validateWithString);
}
}
public class StartWithValidator : IValidator
{
public bool Validate(object value, object validateWith)
{
string valueString = Convert.ToString(value);
string validateWithString = Convert.ToString(validateWith);
return valueString.StartsWith(validateWithString);
}
}
public class LengthValidator : IValidator
{
public bool Validate(object value, object validateWith)
{
string valueString = Convert.ToString(value);
int valueLength = Convert.ToInt32(validateWith);
return (valueString.Length == valueLength);
}
}
public class LessThanValidator : IValidator
{
public bool Validate(object value, object validateWith)
{
decimal valueDecimal = Convert.ToDecimal(value);
decimal validateWithDecimal = Convert.ToDecimal(validateWith);
return (valueDecimal < validateWithDecimal);
}
}
public class MoreThanValidator : IValidator
{
public bool Validate(object value, object validateWith)
{
decimal valueDecimal = Convert.ToDecimal(value);
decimal validateWithDecimal = Convert.ToDecimal(validateWith);
return (valueDecimal > validateWithDecimal);
}
}
public class EqualValidator : IValidator
{
public bool Validate(object value, object validateWith)
{
string valueString = Convert.ToString(value);
string validateWithString = Convert.ToString(validateWith);
return (valueString == validateWithString);
}
}
And usages
class Program
{
static void Main(string[] args)
{
//set up students
var student1 = new Student() { Age = 20, AverageMark = 5, Name = "Ihor", University = "Lviv National University" };
var student2 = new Student() { Age = 20, AverageMark = 5, Name = "SomeLongName", University = "Lviv National University" };
var student3 = new Student() { Age = 20, AverageMark = 5, Name = "Taras", University = "Kyiv National University" };
var student4 = new Student() { Age = 20, AverageMark = 5, Name = "Marko", University = "Some University" };
var student5 = new Student() { Age = 20, AverageMark = 4, Name = "Tanya", University = "Lviv National University" };
var student6 = new Student() { Age = 22, AverageMark = 4, Name = "Ira", University = "" };
var students = new List<Student>() { student1, student2, student3, student4, student5, student6 };
//set up validation rules
var criteria1 = new Criteria("Age", "Equal", "20");
var criteria2 = new Criteria("AverageMark", "MoreThen", "4");
var criteria3 = new Criteria("University", "Contains", "National");
var criteria4 = new Criteria("University", "StartWith", "Lviv");
var criteria5 = new Criteria("Name", "Length", "4");
var criterias = new List<Criteria>() { criteria1, criteria2, criteria3, criteria4, criteria5 };
var result = new List<Student>();
foreach (var currentStudent in students)
{
var isValid = true;
foreach (var currentCriteria in criterias)
{
object currentPropertyValue = typeof(Student).GetProperty(currentCriteria.PropertyName).GetValue(currentStudent);
IValidator currentValidator = ValidatorFactory.GetValidator(currentCriteria.OperationName);
bool validationResult = currentValidator.Validate(currentPropertyValue, currentCriteria.OperationValue);
if (!validationResult)
{
isValid = false;
break;
}
}
if (isValid)
result.Add(currentStudent);
}
}
}
In the end the the code of ValidatorFactory
public class ValidatorFactory
{
public static IValidator GetValidator(string validatorName)
{
validatorName = validatorName.ToUpper();
switch (validatorName)
{
case "CONTAINS": return new ContainsValidator();
case "STARTWITH": return new StartWithValidator();
case "EQUAL": return new EqualValidator();
case "MORETHEN": return new MoreThanValidator();
case "LENGTH": return new LengthValidator();
default: throw new Exception("There are not appropriate validator.");
}
}
}
Maybe this will help someone in the future :)

Categories