I'm trying to compare 2 object arrays to check whether the values have changed between them. e.g.
var oldState = new object[] { 1, "Lee", 0, new UserProfile { FirstName = "Lee",
LastName = "Timmins" }, new Role { RoleID = 1, RoleName "User" } };
var newState = new object[] { 1, "Lee", 1, new UserProfile { FirstName = "Lee",
LastName = "Timmins" }, new Role { RoleID = 1, RoleName = "User" } };
Each item in the array represents a value for a property from the User class below (in the order they are defined):
public class User {
public int UserID { get; set; }
public string UserName { get; set; }
[IgnoreAudit]
public int NumViews { get; set; }
[ChildAudit]
public UserProfile Profile { get; set; }
public Role Role { get; set; }
}
public class UserProfile {
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Role {
public int RoleID { get; set; }
public string RoleName { get; set; }
}
I need to create a method to compare the 2 objects. e.g.
public bool IsDirty(object[] oldState, object[] newState) {
// Comparision code here
}
The complicated part is that it only compares the simple properties that don't have the IgnoreAudit attribute applied to them and only compares complex properties that have ChildAudit attribute applied.
Therefore from the example above the Profile property would be recursively compared (since it has the ChildAudit attribute applied) whereas the Role property wouldn't. Also say if NumViews is the only value that changes between the old and new state IsDirty would return false (since it has the IgnoreAudit attribute applied).
To help you further, given the old state above here is a few examples of the new state and whether IsDirty would return true or false:
// False - since only NumViews changed
var newState1 = new object[] { 1, "Lee", 1, new UserProfile { FirstName = "Lee",
LastName = "Timmins" }, new Role { RoleID = 1, RoleName = "User" } };
// True - since Username has changed
var newState2 = new object[] { 1, "Lee2", 1, new UserProfile { FirstName = "Lee",
LastName = "Timmins" }, new Role { RoleID = 1, RoleName = "User" } };
// True - since Profile.FirstName has changed
var newState3 = new object[] { 1, "Lee", 1, new UserProfile { FirstName = "Paul",
LastName = "Timmins" }, new Role { RoleID = 1, RoleName = "User" } };
// False - since only Role.RoleName has changed
var newState4 = new object[] { 1, "Lee", 1, new UserProfile { FirstName = "Lee",
LastName = "Timmins" }, new Role { RoleID = 1, RoleName = "Admin" } };
I hope i've made my intentions clear. Please feel free to comment if there's any additional information you require.
Appreciate the helps. Thanks
You can use the IComparable Interface to determine if two classes are equal.
class Program
{
static void Main(string[] args)
{
var newState1 = new User
{
UserId = 1,
UserName = "Lee",
NumViews = 1,
Profile = new UserProfile
{
FirstName = "Lee",
LastName = "Timmins"
},
RoleMember = new Role {RoleId = 1, RoleName = "User"}
};
// True - since Username has changed
var newState2 = new User
{
UserId = 1,
UserName = "Lee2",
NumViews = 1,
Profile = new UserProfile
{
FirstName = "Lee",
LastName = "Timmins"
},
RoleMember = new Role {RoleId = 1, RoleName = "User"}
};
//Will show 1 or -1 if not state has change. If == 0 then state has not changed.
Console.WriteLine("Has State1 Changed? : {0}", newState1.CompareTo(newState2));
Console.ReadLine();
}
public class User : IComparable<User>
{
public int UserId { get; set; }
public string UserName { get; set; }
public int NumViews { get; set; }
public UserProfile Profile { get; set; }
public Role RoleMember { get; set; }
#region Implementation of IComparable<in User>
public int CompareTo(User other)
{
if (UserId.CompareTo(other.UserId) != 0)
{
return UserId.CompareTo(other.UserId);
}
if (UserName.CompareTo(other.UserName) != 0)
{
return UserName.CompareTo(other.UserName);
}
if (NumViews.CompareTo(other.NumViews) != 0)
{
return NumViews.CompareTo(other.NumViews);
}
if (Profile.CompareTo(other.Profile) != 0)
{
return Profile.CompareTo(other.Profile);
}
return RoleMember.CompareTo(other.RoleMember) != 0 ? RoleMember.CompareTo(other.RoleMember) : 0;
}
#endregion
}
public class UserProfile : IComparable<UserProfile>
{
public string FirstName { get; set; }
public string LastName { get; set; }
#region Implementation of IComparable<in UserProfile>
public int CompareTo(UserProfile other)
{
return FirstName.CompareTo(other.FirstName) == 0 ? LastName.CompareTo(other.LastName) : FirstName.CompareTo(other.FirstName);
}
#endregion
}
public class Role : IComparable<Role>
{
public int RoleId { get; set; }
public string RoleName { get; set; }
#region Implementation of IComparable<in Role>
public int CompareTo(Role other)
{
return RoleId.CompareTo(other.RoleId) == 0 ? RoleName.CompareTo(other.RoleName) : RoleId.CompareTo(other.RoleId);
}
#endregion
}
}
Related
As I understand it, ComboBox columns are more dynamic for binding in DataGridView than standard columns, and this flexibility can be used to use DisplayMembers from second-order properties. This approach is the first mentioned here by Mr. Aghaei.
However, I'm not getting it right. My application still throws the exception that "Name" doesn't exist.
public void CreateEmployeeTable()
{
DataGridViewComboBoxColumn jobTitleColumn = new DataGridViewComboBoxColumn();
jobTitleColumn.HeaderText = "Job Title";
jobTitleColumn.DataPropertyName = "JobTitle";
jobTitleColumn.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;
jobTitleColumn.DataPropertyName = "ID";
jobTitleColumn.DataSource = globalEmployeeList;
jobTitleColumn.ValueMember = "ID";
jobTitleColumn.DisplayMember = "Name";
jobTitleColumn.ReadOnly = true;
employeeGridView.AutoGenerateColumns = false;
employeeGridView.ColumnCount = 2;
employeeGridView.Columns[0].HeaderText = "Employee ID";
employeeGridView.Columns[0].DisplayIndex = 0;
employeeGridView.Columns[0].DataPropertyName = "ID";
employeeGridView.Columns[1].HeaderText = "Name";
employeeGridView.Columns[1].DataPropertyName = "ListView";
employeeGridView.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
employeeGridView.Columns.Add(jobTitleColumn);
employeeGridView.DataSource = globalEmployeeList;
}
Here is the class definition:
public class EmployeeModel
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Nickname { get; set; }
public DepartmentModel Department { get; set; }
public TitleModel JobTitle { get; set; }
public DateTime HireDate { get; set; }
public List<EmailModel> EmailList { get; set; } = new List<EmailModel>();
public List<PhoneModel> PhoneList { get; set; } = new List<PhoneModel>();
public List<RestrictionModel> RestrictionsList { get; set; } = new List<RestrictionModel>();
public List<CitationModel> CitationsList { get; set; } = new List<CitationModel>();
public List<CertificationModel> CertificationList { get; set; } = new List<CertificationModel>();
public string ListView
{
get
{
return $"{LastName}, {FirstName}";
}
}
public string ToEmailString()
{
IEnumerable<string> employeeEmailStrings = EmailList.Select(emmod => emmod.ToString());
string employeeEmailString = string.Join($"{Environment.NewLine}", employeeEmailStrings);
IEnumerable<string> certificationStrings = CertificationList.Select(clistmod => clistmod.ToString());
string certificationString = string.Join($"{Environment.NewLine}", certificationStrings);
IEnumerable<string> phoneStrings = PhoneList.Select(plistmod => plistmod.ToString());
string phoneString = string.Join($"{Environment.NewLine}", phoneStrings);
return $"{FirstName}, {LastName}: {Environment.NewLine} -{JobTitle.Name}- {Environment.NewLine} {employeeEmailString} {Environment.NewLine} {certificationString} {Environment.NewLine} {phoneString}";
}
public class EmailModel
{
public int ID { get; set; }
public string Address { get; set; }
public string Type { get; set; }
public override string ToString()
{
return $"{Address} ({Type})";
}
}
public class PhoneModel
{
public int ID { get; set; }
public string Number { get; set; }
public string Type { get; set; }
public override string ToString()
{
return $"{Number} ({Type})";
}
}
}
And the definition for TitleModel:
public class TitleModel
{
public string Name { get; set; }
public int ID { get; set; }
}
}
To support the post Show Properties of a Navigation Property in DataGridView (Second Level Properties) I've already shared a few example in the same post or this one which allows showing second level properties and allow editing them.
Here I will share a few more examples, each example has been written as a minimal complete verifiable example, you can just copy and paste in an empty form and they will work.
These are the examples:
Using ToString()
Using CellFormatting
Using ComboBox Column for Navigation Object
Using ComboBox Column for Foreign key column
Example - Using ToString()
When: You don't want to change JobTitle of Employee
How: By overriding ToString method of JobTitle
class JobTitle
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public JobTitle JobTitle { get; set; }
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var jobTitles = new List<JobTitle>() {
new JobTitle {Id= 1, Name="Manager" },
new JobTitle {Id= 2, Name="Employee" },
};
var employees = new List<Employee>() {
new Employee{ Id = 1, Name ="John", JobTitle = jobTitles[0] },
new Employee{ Id = 2, Name ="Jane", JobTitle = jobTitles[1] },
new Employee{ Id = 3, Name ="Jack", JobTitle = jobTitles[1] },
};
var dg = new DataGridView();
dg.Dock = DockStyle.Fill;
dg.DataSource = employees;
this.Controls.Add(dg);
}
Example - Using CellFormatting
When: You don't want to change JobTitle of Employee
How: By handling CellFormatting event of DataGridView and setting Value of the event args to a string representation of JobTitle
class JobTitle
{
public int Id { get; set; }
public string Name { get; set; }
}
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public JobTitle JobTitle { get; set; }
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var jobTitles = new List<JobTitle>() {
new JobTitle {Id= 1, Name="Manager" },
new JobTitle {Id= 2, Name="Employee" },
};
var employees = new List<Employee>() {
new Employee{ Id = 1, Name ="John", JobTitle = jobTitles[0] },
new Employee{ Id = 2, Name ="Jane", JobTitle = jobTitles[1] },
new Employee{ Id = 3, Name ="Jack", JobTitle = jobTitles[1] },
};
var dg = new DataGridView();
dg.Dock = DockStyle.Fill;
dg.DataSource = employees;
dg.CellFormatting += (obj, args) =>
{
if (args.RowIndex >= 0 &&
dg.Columns[args.ColumnIndex].DataPropertyName == "JobTitle")
args.Value = ((Employee)dg.Rows[args.RowIndex].DataBoundItem).JobTitle.Name;
};
this.Controls.Add(dg);
}
Example - Using ComboBox Column for Foreign key column
When: You want to be able to change the JobTitle of Employee and you have the foreign key column in your model.
How: Using a DataGridViewComboBoxColumn for that property, having a data source containing all job titles, and setting DisplayMember and ValueMember to proper properties.
class JobTitle
{
public int Id { get; set; }
public string Name { get; set; }
}
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int JobTitleId { get; set; }
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var jobTitles = new List<JobTitle>() {
new JobTitle {Id= 1, Name="Manager" },
new JobTitle {Id= 2, Name="Employee" },
};
var employees = new List<Employee>() {
new Employee{ Id = 1, Name ="John", JobTitleId = 1 },
new Employee{ Id = 2, Name ="Jane", JobTitleId = 2 },
new Employee{ Id = 2, Name ="Jack", JobTitleId = 2 },
};
var dg = new DataGridView();
dg.Dock = DockStyle.Fill;
dg.DataSource = employees;
dg.Columns.Add(new DataGridViewTextBoxColumn()
{
DataPropertyName = "Id", HeaderText = "Id"
});
dg.Columns.Add(new DataGridViewTextBoxColumn()
{
DataPropertyName = "Name", HeaderText = "Name"
});
dg.Columns.Add(new DataGridViewComboBoxColumn()
{
DataPropertyName = "JobTitleId",
HeaderText = "JobTitleId",
DataSource = jobTitles,
ValueMember = "Id",
DisplayMember = "Name",
});
this.Controls.Add(dg);
}
Example - Using ComboBox Column for Navigation Object
When: You want to be able to change the JobTitle of Employee and you don't have the foreign key column in your model, instead you want to use the navigation object in your model.
How: Using a DataGridViewComboBoxColumn for that property, having a data source containing all job titles, without setting DisplayMember and ValueMember to proper properties. Then handling CellFormatting to set the display value of the cell and handling CellParsing to get value from ComboBox and put into the cell.
class JobTitle
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public JobTitle JobTitle { get; set; }
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var jobTitles = new List<JobTitle>() {
new JobTitle {Id= 1, Name="Manager" },
new JobTitle {Id= 1, Name="Employee" },
};
var employees = new List<Employee>() {
new Employee{ Id = 1, Name ="John", JobTitle = jobTitles[0] },
new Employee{ Id = 2, Name ="Jane", JobTitle = jobTitles[1] },
new Employee{ Id = 2, Name ="Jack", JobTitle = jobTitles[1] },
};
var dg = new DataGridView();
dg.Dock = DockStyle.Fill;
dg.DataSource = employees;
dg.Columns.Add(new DataGridViewTextBoxColumn()
{
DataPropertyName = "Id", HeaderText = "Id"
});
dg.Columns.Add(new DataGridViewTextBoxColumn()
{
DataPropertyName = "Name", HeaderText = "Name"
});
dg.Columns.Add(new DataGridViewComboBoxColumn()
{
DataPropertyName = "JobTitle",
HeaderText = "JobTitle",
DataSource = jobTitles,
});
dg.CellFormatting += (obj, args) =>
{
if (args.RowIndex >= 0 &&
dg.Columns[args.ColumnIndex].DataPropertyName == "JobTitle")
{
args.Value =
((Employee)dg.Rows[args.RowIndex].DataBoundItem).JobTitle.ToString();
}
};
dg.CellParsing += (obj, args) =>
{
if (args.RowIndex >= 0 &&
dg.Columns[args.ColumnIndex].DataPropertyName == "JobTitle")
{
args.Value = ((ComboBox)dg.EditingControl).SelectedItem;
args.ParsingApplied = true;
}
};
this.Controls.Add(dg);
}
Is there a way to add a field to an IQueryable (or List<> or whatever) without having to rewrite an entire "new {list, of, all, fields}". I have a dynamic field who can have different formulas depending on the situation. Here's a basic example :
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
List<User> users = new List<User>();
users.Add(new User { FirstName = "Foo", LastName = "Bar"} );
users.Add(new User { FirstName = "Bar", LastName = "Foo"} );
I would like to add a field later ( just before the output ) without removing or rewriting all the existing fields
var betterUser = users.Select(u => new { FullName = u.FirstName + " " + u.LastName });
This will only return FullName, but I want to keep FirstName and LastName. In my real code, I have about 15 fields and about 1.2 billion rows that will be cleaned up before adding the last field so if I add all possible calculated fields directly to the model, the performance takes a serious hit.
You could do something like this
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public object dynamicField {get; set;}
}
List<User> users = new List<User>();
users.Add(new User { FirstName = "Foo", LastName = "Bar"} );
users.Add(new User { FirstName = "Bar", LastName = "Foo"} );
foreach (var obj in users)
{
obj.dynamicField = obj.FirstName + " " + obj.LastName;
}
This way you would not have to remove or rewrite all the existing fields.
Your user class needs a property to do this: but you can do it:
public class Animal
{
public string Name { get; set; }
public bool HasLegs { get; set; }
public bool IsFoo { get; set; }
public string FooLegs { get; set; }
}
private static string legsString(bool hasLegs)
{
return hasLegs ? "Has Legs" : "Has No Legs";
}
static void Main(string[] args)
{
List<Animal> animals = new List<Animal>()
{
new Animal()
{
Name = "Foo",
HasLegs = true
},
new Animal()
{
Name = "Kangaroo",
HasLegs = true
},
new Animal()
{
Name = "Snake",
HasLegs = false
}
};
var fooAnimals = animals.Select(s => new Animal
{
Name = s.Name,
HasLegs = s.HasLegs,
IsFoo = (s.Name == "Foo" && s.HasLegs),
FooLegs = $"{s.Name} {legsString(s.HasLegs)}"
}).AsQueryable<Animal>();
}
}
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 :)
Using C# with LINQ, how can I merge two lists of different objects, say, Seminar and Conference?
They have some common and some different fields/properties and do not share unique id.
class Seminar
{
int id,
DateTime joinDate,
string name
}
class Conference
{
Guid confNumber,
DateTime joinDate
Type type
}
I have a list of:
List<Seminar>
List<Conference>
I need to merge them into a super List:
List<Object>
A code snippet would be great help.
If you just want a single List<object> containing all objects from both lists, that's fairly simple:
List<object> objectList = seminarList.Cast<object>()
.Concat(conferenceList)
.ToList();
If that's not what you want, then you'll need to define what you mean by "merge".
Following code works fine for me, if this is your definition of Merge
One solution
List<A> someAs = new List<A>() { new A(), new A() };
List<B> someBs = new List<B>() { new B(), new B { something = new A() } };
List<Object> allS = (from x in someAs select (Object)x).ToList();
allS.AddRange((from x in someBs select (Object)x).ToList());
Where A and B are some classes as follows
class A
{
public string someAnotherThing { get; set; }
}
class B
{
public A something { get; set; }
}
Another Solution
List<A> someAs = new List<A>() { new A(), new A() };
List<B> someBs = new List<B>() { new B(), new B { something = string.Empty } };
List<Object> allS = (from x in someAs select (Object)new { someAnotherThing = x.someAnotherThing, something = string.Empty }).ToList();
allS.AddRange((from x in someBs select (Object)new { someAnotherThing = string.Empty, something = x.something}).ToList());
Where A and B are having class definition as
class A
{
public string someAnotherThing { get; set; }
}
class B
{
public string something { get; set; }
}
Simple method of pure code
internal class Person
{
public int Id { get; set; }
public string UserName { get; set; }
}
internal class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
internal class UserPerson
{
public int Id { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
private static void Main(string[] args)
{
Person[] people = new Person[3] { new Person { Id = 1, UserName = "AliUserName" }, new Person { Id = 2, UserName = "MortezaUserName" }, new Person { Id = 3, UserName = "SalarUserName" } };
User[] users = new User[4] { new User { FirstName = "ali", LastName = "Barzegari" }, new User { FirstName = "Morteza", LastName = "Sefidi" }, new User { FirstName = "Salar", LastName = "Pirzadeh" }, new User { FirstName = "Babak", LastName = "Hasani" } };
UserPerson[] userPeople = new UserPerson[people.Length > users.Length ? people.Length : users.Length];
if (people.Length > users.Length)
for (int i = 0; i < people.Length; i++)
{
userPeople[i] = new UserPerson
{
Id = people[i].Id,
UserName = people[i].UserName,
FirstName = users.Length <= i ? "" : users[i].FirstName,
LastName = users.Length <= i ? "" : users[i].LastName
};
}
else
for (int i = 0; i < users.Length; i++)
{
userPeople[i] = new UserPerson
{
Id = people.Length <= i ? 0 : people[i].Id,
UserName = people.Length <= i ? "" : people[i].UserName,
FirstName = users[i].FirstName,
LastName = users[i].LastName
};
}
Console.ReadLine();
}
I have three lists that I need to join together
class Person
{
public int PersonID{ get; set; }
public string FirstName{get; set;}
public string LastName {get; set;}
}
class Traffic
{
public DateTime Date{ get; set; }
public int PersonID;
public int TrafficID;
}
class TrafficType
{
public int TrafficID { get; set; }
public string Description { get; set; }
}
List<Person> Persons=GetPersons();
List<TrafficType> TrafficTypes=GetTrafficTypes();
List<Traffic> Traffics=GetTraffics();
I need an output like:
PersonID FirstName LastName Date Description
1001 David ... 2011/07/19 sample description
from person in Persons
from traffic in traffics
from trafficType in trafficTypes
where trafficType.TrafficID = traffic.TrafficID
where traffic.PersonID = person.PersonID
select new
{
PersonID = person.PersonID,
....
}
var result = Persons.Join(
Traffics,
person => person.PersonID,
trafic => trafic.PersonID,
(person, trafic) => new
{
PersonId = person.PersonID,
FirstName = person.FirstName,
LastName = person.LastName,
Date = trafic.Date,
TraficId = trafic.TrafficID
}).Join(
TrafficTypes,
a => a.TraficId,
traficType => traficType.TrafficID,
(a, traficType) => new
{
PersonId = a.PersonId,
FirstName = a.FirstName,
LastName = a.LastName,
Date = a.Date,
Description = traficType.Description
});
Here's a complete code sample with Linq query expression code that should get exactly what you're looking for:
using System;
using System.Collections.Generic;
using System.Linq;
class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Traffic
{
public DateTime Date { get; set; }
public int PersonId { get; set; }
public int TrafficId { get; set; }
}
class TrafficType
{
public int Id { get; set; }
public string Description { get; set; }
}
class Program
{
static void Main(string[] args)
{
var persons = new List<Person>()
{
new Person()
{
Id = 1001,
FirstName = "David",
LastName = "Jones",
},
};
var trafficTypes = new List<TrafficType>()
{
new TrafficType()
{
Id = 456,
Description = "sample description",
},
};
var traffics = new List<Traffic>()
{
new Traffic()
{
PersonId = 1001,
TrafficId = 456,
Date = DateTime.Now,
},
};
var joinedData = from p in persons
from t in traffics
from tt in trafficTypes
where p.Id == t.PersonId
&& tt.Id == t.TrafficId
select new
{
PersonId = p.Id,
FirstName = p.FirstName,
LastName = p.LastName,
// Remove time component, if present
Date = t.Date.Date,
Description = tt.Description,
};
foreach (var item in joinedData)
{
Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}"
, item.PersonId
, item.FirstName
, item.LastName
, item.Date.ToShortDateString() // Don't print the time
, item.Description
);
}
}
}
The program output is:
1001 David Jones 7/19/2011 sample description
You can put them all in a class e.g. (Problem), then use a method for your output.
class Problem
{
public Problem()
{
}
public void Show()
{
// implement your output here
}
}
Or, if you are using Windows Forms app and interisting in Tables, you can use DataGridView control. For more information about it, visit http://msdn.microsoft.com/en-us/library/e0ywh3cz.aspx
Or, use DataGrid: http://www.codeproject.com/KB/grid/usingdatagrid.aspx