I have what seems to be a simple problem, but am unable to come up with a clean solution.
I have a two classes which looks like below
Class Person{
String name{get; set;}
int age{get; set;}
}
Class Alien{
String alienName{ get; set}
int alienAge{get; set;}
}
These classes are thirdparty classes that I have to use, have no control over. But at some point I would want to be able to construct a Alien object given a Person object and vice versa. I have only two properties in my example. In real life I may have upto 50 properties for both Alien and Person.
Alien is not a subset of Person and Person is not a subset of alien. Those are just two different objects. What do you guys think is the best way to transform these objects between each other. I don't want to laboriously write a copy method that takes in each property and sets its equivalent property in the other. Since the method names can be vastly different between those two classes, I don't think I might be able to use reflection either. Ideally am looking for something which would externalize the copy procedure so that if something changes in Alien or Person object in the future, I wouldn't have to change my logic.
Any suggestions?
Thanks
K
You might want to look at AutoMapper
Use Interfaces. If you have an Interface, certain properties that you must to be copied are already defined:
Interface ISubject
{
// properties
String name {get; set;}
int age {get; set;}
}
Class Person : ISubject
{
// contractors
public Person ()
{
...
}
public Person (ISubject subject)
{
name = subject.name;
age = subject.age;
}
...
}
Class Alien : ISubject
{
// contractors
public Alien ()
{
...
}
public Alien (ISubject subject)
{
name = subject.name;
age = subject.age;
}
...
}
and when you using:
var person = new Person();
...
ISubject subject = (ISubject) person;
var name = subject.name;
or
var person = new Person();
...
Alien subject = new Alien(person);
var name = alien.name;
You can try http://code.google.com/p/nutil/ , there is a class named BeanUtils, that have a method to copy properties.
Related
I'm currently looking into inheritance and polymorphism and I'm a bit confused about where you'd want to create a Person object of type Student?
assuming the following code:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
}
class Student : Person
{
public int YearOfStudy { get; set; }
public string Course { get; set; }
public string PredictedGrade { get; set; }
}
Now looking online, there are a few options here in terms of creating an object:
Person p = new Person();
Student s = new Student();
Person ps = new Student();
The first objects allows me to set name, age and gender, while the second allows me to set those 3, as well as yearsOfStudy, course and predictedGrade. But I'm unsure of what the third object allows me to do? I can still set all 6 parameters, however I can only use the attributes set in the Person class? Any explanation on the correct usage of the third object would be appreciated.
Thanks
Don't think of this as Person ps = new Student() yet.
The real benefit is being able to abstract common code for all types of Person. So your methods may take in a Person because that's all it needs and will work with any person type you create such as Janitor, Teacher, etc.
var myStudent = new Student()
VerifyAge(myStudent);
VerifyYearOfStudy(myStudent);
public bool VerifyAge(Person person)
{
return person.Age < 200;
}
public bool VerifyYearOfStudy(Student student)
{
return student.YearOfStudy <= DateTime.Now.Year;
}
To clear up some confusion the only time you ever really declare the base in a method is when you want to actually denote that this variable is only meant to be used as that specific type. Think of it as if you had declared your variable using an interface instead. Sure I am working with a Student instance, but I am only working with it as a Person instance or as IPerson.
Normally as a variable in a method you wouldn't do that because pretty much the defacto standard is to just use var for everything nowadays. Where you do make the choice to define Person is normally on properties, method return values, and method parameters. Local variable is not really important.
Because Student class is derived from Person class, any Student object is also a Person object. Thus a notation Person ps = new Student(); means we're declaring variable ps to be of type Person and instantiate it as Student. It could be used if you have a method that takes Person object as parameter, e.g.
public void Foo(Person p) { if(p.Age > 21) Console.WriteLine("OK to drink!"); }
However, if you have a method that operates on properties of derived class you must declare and instantiate the instance of it. So for
public void Foo(Student s) {if(s.YearOfStudy == 1) Console.WriteLine("Freshman"); }
you must use Student s = new Student();.
Say I have one class that looks like this:
public class Person
{
public string Name {get; set;}
public int Number {get; set;}
}
And another that looks like this:
public class Dog
{
public string Name {get; set;}
public int Number {get; set;}
}
They are two different classes, but they happen to have the exact same elements (a string called Name and an int called Number)
Is there an easy way in C# to, say, if I had an instance of Person to then create an instance of Dog with the same Name and Number?
For example if I had:
Person person = new Person();
person.Name = "George";
person.Number = 1;
I know I can't simply go:
Dog dog = person;
Because they are two different types. But is there a way in C# to check "oh, if they have the same element, set the same elements of Dog to equal that of Person.
But I feel there has to be an easier way than doing something like:
dog.Name = person.Name;
dog.Number = person.Number;
Especially if the class has a LOT of elements. Also if anyone is wondering, these two different classes are in two different pieces of the API, so I can't simply make them related either.
You can use AutoMapper:
public Dog UsingAMR(Person prs)
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Person, Dog>();
});
IMapper mapper = config.CreateMapper();
return mapper.Map<Person, Dog>(prs);
}
Then you can easily:
Person ps = new Person {Name = "John", Number = 25};
Dog dog = UsingAMR(ps);
Just don't forget to install AutoMapper first from the package manager console as mentioned in the reference:
From Tools menu click on NuGet Package Manager ==> Package Manager Console
Then type the following command:
PM> Install-Package AutoMapper
An object oriented approach.
public class Mammal
{
public Mammal(Mammal toCopy)
{
Name = toCopy.Name;
Number = toCopy.Number;
}
public string Name {get; set;}
public int Number {get; set;}
}
public class Person: Mammal
{
public Person(Mammal toCopy) {} /* will default to base constructor */
}
public class Dog: Mammal
{
public Dog(Mammal toCopy) {} /* will default to base constructor */
}
This will allow the following:
Person person = new Person();
person.Name = "George";
person.Number = 1;
Dog dog = new Dog(person);
Install AutoMapper package in your project.
As a best practice (for web applications) you can create new class (should derives from Profile) in your App_Start folder, that will contain all your mappings for your project.
namespace MyApp.App_Start
{
public class MyAppMapping : Profile
{
public MyAppMapping()
{
CreateMap<Person, Dog>();
//You can also create a reverse mapping
CreateMap<Dog, Person>();
/*You can also map claculated value for your destination.
Example: you want to append "d-" before the value that will be
mapped to Name property of the dog*/
CreateMap<Person, Dog>()
.ForMember(d => d.Days,
conf => conf.ResolveUsing(AppendDogName));
}
private static object AppendDogName(Person person)
{
return "d-" + person.Name;
}
}
}
Then Initialize your mapping inside the Application_Start method in Global.asax
protected void Application_Start()
{
Mapper.Initialize(m => m.AddProfile<MyAppMapping>());
}
You can now use the mappings that you have created
var dog = AutoMapper.Mapper.Map<Person, Dog>(person);
If you don't work with big generic list, you can do it using LinQ.
var persons = new List<Person>();
// populate data [...]
var dogs = persons.Select(p=>new Dog{Name=p.Name,Number=p.Number}).ToList();
It's easy to remember, and you can filter data previously.
Let's say I have an ObservableCollection<Person>.
Now, every student can have some sort of opinion on every other person. What would be the best way to code something like this, so that it's accessible from both objects?
I thought about something like this for a relations:
enum RelationPoint { Neutral, Like, Dislike, Love, Hate }
List<RelationPoint> relation;
How can I define something like this for every person?
You could create an object, which stores the opinion in an object, like this:
public class Opinion
{
public Person Destination
{
get;
set;
}
public Person Target
{
get;
set;
}
public RelationPoint RelationType
{
get;
set;
}
}
If you store them like this in a list, every person can have an opinion abount another pserson.
To figure out, which person has which optinion, you can simply find this out using linq:
var goodRelation = listOfOption.Where(item => item.RelationType == RelationPoint.Like && item.Destination = <<Some Person>>);
Now you know, which person the Destination likes.
One solution would be to make an object called "Relation" which contains 2 persons.
So you would have following classes:
public class Person
{
public String Name;
....
}
and a class "Relation:
public class Relation
{
private Person p1;
private Person p2;
private String opinion;
}
Now you could make sth. like this:
Person p = new Person ("John");
Person p2 = new Person ("David");
Relation r1 = new Relation(p, p2, "Neutral");
Just one of many solutions.
I'm feeling a little led by MVC and Entity framework... so I need help
The problem is I have 2 types of model: Person, Sausage
A Person can be made without any relationships to a sausage, similarly
a Sausage can be made without any relationships to a person.
When you go to a Person, you can add sausages he has eaten.
A sausage can be eaten by many people.
I have created 3 SQL tables:
People
Sausages
Sausages_People (the relationship table which has 2 foreign keys relating to People and to Sausages tables)
I have also created 2 classes:
Person
Sausage
A Person can eat multiple sausages so I did this:
class Person
{
IEnumerable<Sausage> Sausages { get; set; }
}
But using my entity framework DbContext, I am confused at how to link this up to the database...
I am creating database tables first then coding classes (migrations are off)
class EFDbContext : DbContext
{
public DbSet<Sausage> Sausages { get; set; }
public DbSet<Person> People { get; set; }
// I guess I need a relationship table stated here too right? so:
public DbSet<Sausage_Person> Sausages_People { get; set; }
// Is this right?
}
That means I need a separate class:
class Sausage_Person
{
public int SausageID { get; set; }
public int PersonID { get; set; }
}
Does that mean after all this, I actually want my Person to have a property like this:
class Person
{
IEnumerable<Sausage_Person> Sausages { get; set; }
}
What's the usually technique for this?
When I now go to a Person and add a Sausage to him, do I just have to add a new repository method
AddSausagePersonRelation( int sausageID, int personID ){ ... }
Do I not need the IEnumerable?
you are pretty close...
but i personally would avoid the int constructors since iny,int is ambiguous... maybe try
AddSausagePersonRelation( Sausage s, Person p ){ ... }
i would not put any IEnumerable in Person for the sausages...
You do need the IEnumerable. The problem in your situation, I think, is that you are still thinking in terms of the database architecture and are including the intermediate table that links people and sausages in your object model. It is entirely unnecessary.
Let's say you are using a CodeFirst approach (I advice you to do so whenever the project makes it feasible). Then your thinking should go like this:
"Ok, so I have people and sausages. People can have 0 sausages and a sausage can be nobody's (it can be without an owner). So basically the linking infrastructure between them should be many-to-many with the possibility of no connections. What data structure do I need to represent this (it should be able to contain 0 or more references to the other class)? Well, IEnumerable/ICollection should do the trick."
Thus, you have the classes:
public class Person()
{
IEnumerable<Sausage> Sausages { get; set; }
public Person()
{
this.Sausages = new HashSet<Sausage>();
}
}
public class Sausage()
{
IEnumerable<Person> People { get; set; }
public Person()
{
this.People = new HashSet<People>();
}
}
If you are using CodeFirst as your approach, the table with the IDs that makes possible expressing the many-to-many relationship in terms of SQL Database design will be automatically generated by EntityFramework.
Edit:
As someone mentioned in the comments, a sausage can indeed be considered property of only one person (excluding more complicated situations like sharing, etc.). In this case, it is perfectly OK to have something like:
public class Person()
{
IEnumerable<Sausage> Sausages { get; set; }
public Person()
{
this.Sausages = new HashSet<Sausage>();
}
}
public class Sausage()
{
Person Person { get; set; }
}
Again, EntityFramework in case of CodeFirst will generate the tables you need in this situation. You, of course, can assume control over the exact details of that process by using CodeFirst Data Annotations or FluentAPI.
Use an ICollection so that you can add to it:
class Person
{
IEnumerable<Sausage_Person> Sausages { get; set; }
}
Make sure to initialize it in the constructor:
Sausages = new HashSet<Sausage_Person> = new HashSet<Sausage_Person>();
To Add a Sausage to a Person you could just Add it to Sausages or you could write a method like this:
public void AddExistingSausage{Sausage sausage}
{
var personSausage = new PersonSausage{PersonID = this.ID, SausageID = Sausage.ID};
this.Sausages.Add(personSausage);
}
However, the above method depends on the sausage parameter being an existing Sausage.
Suppose I have a List of Person (which is a class). It contains about 20 field (Name, Surname, Age, DateOfBirthdate, and so on). So I got this list:
var listOfPersons= MyContext.Persons.Cast<Person>();
Now, I need to iterate through this List, and for each Person adding a new field (which it is not present in the class), called, let's say, CurrentDateTime.
I could create a new object, with the new field, and "copy & paste" values from Person to the new Class. Somethings like:
PersonNew newPerson = new PersonNew("Name", "Surname", "Age", "DateOfBirthdate", ... "CurrentDateTime");
But this is very bad if in the future I change the Person class. So, is there a strategy to "extending Person" with a new field? That takes the Person instance (whatever it is) and adds the new field?
You can create some static method that create PersonNew from Person using Automapper.
public class PersonNew : Person
{
public static PersonNew CreateFromPerson(Person person, DateTime currentDateTime)
{
var newPerson = Mapper.Map<PersonNew>(person);
newPerson.CurrentDateTime = currentDateTime;
}
}
I think that the solution you described works fine. If you want to keep track of each person's birthday without extending the Person class, you might use a Dictionary object
var listOfPersons = MyContext.Perons.Cast<Person>();
Dictionary<Person, DateTime> birthdays = new Dictionary<Person, DateTime>
foreach(Person person in listOfPersons)
{
birthdays.Add(person, getBirthday(person);
}
One solution is to make your class partial, and add your field in another partial definition of your class:
public partial class Person
{
public string Name { get; set; }
public string FirstName { get; set; }
...
}
...
public partial class Person
{
public DateTime CurrentDateTime { get; set; }
}
...
var listOfPersons = MyContext.Persons.Cast<Person>();
foreach (var person in listOfPersons)
{
person.CurrentDateTime = ....
}
Do note that you will use the same instance of your class.
First I would suggest using extension methods for projecting collections instead of iterating. Like that:
var newCollection = oldCollection.Select(entity => MakeNewType(entity))
Second, it's not completely clear what you mean by "extending Person" with a new field. Here are the couple of ways you can accomplish that.
1) Make another class with the new field and map it to the old one. This is a common scenario for asp.net mvc application where you map models to the appropriate viewmodels. Automapper is useful for these types of scenario (see Sławomir Rosiek anwser)
2) Take advantage of dlr in c# 4+. Yuo will lose the intellisense for dynamic objects, but they canned be passed around functions
var newPeople = people.Select(p =>
{
dynamic expando = new ExpandoObject();
expando.Id = p.Id;
expando.FirtName = p.FirtName;
/* ... */
expando.CurrentDateTime = DateTime.Now;
return expando;
});
3) Use Anonymous types. Anonymous types cannot be passed to another functions, so this approach is useful when you need to quickly project data inside a single method and calculate some result
var newPeople = people.Select(p => new
{
Id = p.Id,
FirtName = p.FirtName,
/* ... */
CurrentDateTime = DateTime.Now
});
in both cases you can now access newly "created" property:
foreach(var p in newPeople)
{
Console.WriteLine("CurrentDateTime: {0}", p.CurrentDateTime);
}
4) If you really need to create a fully featured .net class at runtime you can use Reflection.Emit. This scenario is typically used to create dynamic proxies - subclasses which implement some functionality only known at runtime. Entity framework does this.