Aaron
Aaron

Reputation: 1832

inheritance in C#: create an instance initialized with values of a superclass instance

I'm pretty sure this is impossible, but here goes..

I have a custom class in C# called Person which has a few properties such as Age, Height etc.

I then make a new class called Employee which inherits from Person but I don't yet add any other properties to Employee. So its basically just a Person still, except its called an Employee.

Now say I have an instance of Person called SomePerson. How can I create a new Employee instance that has all of the values it inherited from Person, set to those inside SomePerson. Like casting from a Person into an Employee.. But without me having to manually specify each and every property that needs to be set..

Something like..

Employee NewEmployee = (Employee)SomePerson;

But of course you get the error saying "Can't convert a Person into an Employee" etc.

Is AutoMapper the only practical solution to do things like this if you say had 300 properties in the involved objects??

UPDATE:

Auto-Mapper doesn't seem to handle my objects..

Employee SomeEmployee = EmployeeRepository.GetEmployee(SomeEmployeeID);

// Populate the ViewModel with the Person fetched from the db, ready for editing..
VMEmployee EmployeeToEdit = Mapper.Map<Employee, VMEmployee>(SomeEmployee);


// ViewModel based on Employee with Validation applied..
[MetadataType(typeof(Employee_Validation))]
public class VMEmployee : Employee
{
    // Absolutely nothing here
}

where "Employee" is auto-generated by LINQ to SQL..

Upvotes: 4

Views: 1661

Answers (6)

Allon Guralnek
Allon Guralnek

Reputation: 16121

"they are complex LINQ to SQL Model classes" -- Aaron

If you have a table that maps to one of several possible classes, you can use LINQ to SQL's Inheritance Hierarchies. It means that if you use the same table for several types of conceptual entities, you can have LINQ to SQL automatically create the appropriate class. Each class can have different properties which can be a subset of the columns in the table.

There are some limitations. You can use only one table per inheritance hierarchy and you must have a discriminator column that tells LINQ to SQL which class should be used.

Upvotes: 0

Ryan
Ryan

Reputation: 1382

If you have relatively simple properties, reflection will probably be the quickest and easiest solution to map property values.

Contrary to popular belief, reflection really isn't that bad; Rick Strahl dispels this myth in this article: http://www.west-wind.com/weblog/posts/351.aspx.

Create the following constructor for Employee:

public Employee(Person person)
{
    // clone property values
    foreach (var property in person.GetType().GetProperties().Where(property => property.CanRead && property.CanWrite))
    {
        property.SetValue(this, property.GetValue(user, null), null);
    }
}

Now simply instantiate an Employee object like so:

Employee NewEmployee = new Employee(SomePerson);

Upvotes: 0

Pete Kirkham
Pete Kirkham

Reputation: 49311

When you start a new job, is a new person born who is not you, and the old you killed?

If your design is based on that scenario, as it appears, then the practice in your organisation is very strange.

Instead, a person has an employment relationship with an employer.

Don't use inheritance to model roles; allow the same person to have roles which represent their relationships with other objects.

Upvotes: -2

Pop Catalin
Pop Catalin

Reputation: 62930

You can use automaper for this purpose, without any configuration.

here's an example:

Employee employee = Mapper.Map<Person, Employee>(person);

Upvotes: 1

Matthew Abbott
Matthew Abbott

Reputation: 61589

AutoMapper is a good solution in this case. If you're not going to use a property mapping framework, and you're not willing to create a copy constructor public Employee(Person person), or an implicit/explicit conversion, how else do you expect to copy the properties across. Realistically you could

1.Reflection

public void Map<TSource, TDestination>(TSource source, TDestination destination)
{
  var props = typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance);
  var type = typeof(TDestination);

  foreach (var prop in props)
  {
    object value = prop.GetValue(source, null);

    var prop2 = type.GetProperty(prop.Name);
    if (prop2 == null)
      continue;

    if (prop.PropertyType != prop2.PropertyType)
      continue;

    prop2.SetValue(destination, value, null);
  }
}

2.Copy Constructor

public Employee(Person person)
{
  // Copy properties
}

3.Implicit/Explicit Conversion

public static implicit operator Employee(Person person)
{
  // Build instance and return
}

4.AutoMapper

Mapper.Map<Person, Employee>(person);

5.Combination of 3/4:

public static implicit operator Employee(Person person)
{
  return Mapper.Map<Person, Employee>(person);
}

A note on implicit/explicit conversion operators: I believe in using these you won't be generating CLS-compliant code.

As @Mitch Wheat has already said, if you have an object with over 300 properties, I would reconsider what that object actually represents. Refactor refactor refactor.

Upvotes: 4

Mitch Wheat
Mitch Wheat

Reputation: 300539

Create a constructor on Employee that takes a Person instance. Of course you'll have to fill in all the properties (maybe Resharper can help?)

Upvotes: 0

Related Questions