Introduction
Casting and converting objects from type to type is an integral part of object oriented programming. When dealing with types in an inheritance chain, objects can be easily cast into a higher level. However, casting an object down into a derived type is not so easy. In many cases, it's not possible at all; however, there are specific circumstances where you may have this requirement.
Background
Recently, I had the need to convert an object into a descending type. The base type is a simple data object, with public properties representing values of private fields. The derived type has a few additional properties added on. I wanted to use the derived type as the data source for a grid, but my data manager only gave me the base type. My goal was to convert the base type into the derived type, then just fill in the missing properties.
I found that there really was no easy way to do this, without resorting to either converting the values one at a time, or using alternate methods such as reflection or serialization.
Suppose I have the following situation:
class Foo {
public int Prop1 { get; set; }
public int Prop2 { get; set; }
}
class Bar : Foo {
public int Prop3 { get; set; }
}
static IEnumerable<Bar> ConvertToBar(List<Foo> foos) {
}
The most basic way of accomplishing this is to assign the values one at a time - not bad in our situation, but if I have a bunch of properties in the base, it can get kind of long.
static IEnumerable<Bar> ConvertToBar(IEnumerable<Foo> foos) {
foreach (Foo foo in foos) {
yield return new Bar() { Prop1 = foo.Prop1, Prop2 = foo.Prop2 };
}
}
Doing this every once in a while is no big deal, but if you have to do it a lot, it can add an unnecessary level of complexity to your code, while opening up more room for error. I decided to write a method that will accomplish this without the need for writing your own conversion method.
Using the Code
Converting into a derived class using this technique is only possible in specific circumstances. The class must include properties that have no side effects, and the order of setting these values must not matter. The derived class must contain a parameterless constructor, and there should be no indexer properties. This may seem like a lot of restrictions, but since this technique is designed to work with simple data objects, it's not all that unreasonable.
I built a generic method named ToDerived that accepts an object of one type, and converts to one if its descended classes.
public static TDerived ToDerived<TBase, TDerived>(TBase tBase)
where TDerived : TBase, new()
{
TDerived tDerived = new TDerived();
foreach (PropertyInfo propBase in typeof(TBase).GetProperties())
{
PropertyInfo propDerived = typeof(TDerived).GetProperty(propBase.Name);
propDerived.SetValue(tDerived, propBase.GetValue(tBase, null), null);
}
return tDerived;
}
This is pretty straightforward reflection - I'm retrieving the properties from the base object, then assigning those values to the derived object. When this method is complete, all of the values from the base class will be assigned to, but the ones in only the derived class will still be their default value. In our Foo/Bar example, Prop1 and Prop2 will be transferred, but Prop3 will still be zero (default for int).
Of course, there are more things to think about. Properties can be public, internal, protected, or private. By default, the GetProperties() method only returns public properties. If we want to access other accessibilities, we can accomplish this using the BindingFlags enumeration. Adding a bindingFlags parameter to the method, we give the caller the option of setting exactly what she/he wants to do:
public static TDerived ToDerived<TBase, TDerived>(TBase tBase, BindingFlags bindingFlags)
where TDerived : TBase, new()
{
bool allowNonPublic = ((bindingFlags & BindingFlags.NonPublic) ==
BindingFlags.NonPublic);
TDerived tDerived = new TDerived();
foreach (PropertyInfo propBase in typeof(TBase).GetProperties(bindingFlags))
{
PropertyInfo propDerived = typeof(TDerived).GetProperty
(propBase.Name, bindingFlags);
propDerived.SetValue(tDerived, propBase.GetValue(tBase, null), null);
}
return tDerived;
}
BindingFlags is a little tricky at first - it's a flag enumeration, and you need to define which properties you can find. Here are the two types that I'd be likely to use for this technique:
Bar bar = ToDerived<Foo, Bar>(foo, BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance);
bar = ToDerived<Foo, Bar>(foo, BindingFlags.Public |
BindingFlags.Instance);
Add just a couple more things - pass in an array or other collection of strings representing properties to ignore, mix in some LINQ to objects, exclude index parameters, put it all together, and here's the final product:
public static TDerived ToDerived<TBase, TDerived>
(TBase tBase, BindingFlags bindingFlags, ICollection<string> propertiesToIgnore)
where TDerived : TBase, new()
{
if (tBase == null)
{
throw new ArgumentNullException("tBase");
}
bool allowNonPublic = ((bindingFlags & BindingFlags.NonPublic) ==
BindingFlags.NonPublic);
TDerived tDerived = new TDerived();
var baseProperties =
from propBase in typeof(TBase).GetProperties(bindingFlags)
where ((propertiesToIgnore == null) ||
(!propertiesToIgnore.Contains(propBase.Name)))
where (propBase.GetGetMethod(allowNonPublic) != null)
select propBase;
foreach (PropertyInfo propBase in baseProperties)
{
PropertyInfo propDerived = typeof(TDerived).GetProperty
(propBase.Name, bindingFlags, null, propBase.PropertyType, new Type[0], null);
if (
(propDerived != null)
&& (propDerived.GetSetMethod(allowNonPublic) != null)
&& (propBase.GetIndexParameters().Length == 0)
&& (propDerived.GetIndexParameters().Length == 0)
)
{
propDerived.SetValue(tDerived, propBase.GetValue(tBase, null), null);
}
}
return tDerived;
}
All that's left is a few overloads:
public static TDerived ToDerived<tbase>(TBase tBase)
where TDerived : TBase, new()
{
BindingFlags bindingFlags = BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance;
return ToDerived<tbase>(tBase, bindingFlags);
}
public static TDerived ToDerived<tbase>
(TBase tBase, ICollection<string> propertiesToIgnore)
where TDerived : TBase, new()
{
BindingFlags bindingFlags = BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance;
return ToDerived<tbase>(tBase, bindingFlags, propertiesToIgnore);
}
public static TDerived ToDerived<tbase>(TBase tBase, BindingFlags bindingFlags)
where TDerived : TBase, new()
{
return ToDerived<tbase>(tBase, bindingFlags, null);
}
Conclusion
Reflection isn't the most fun thing to do on the fly, but when using reusable generic code such as this, it's reasonably safe and performs pretty well. There is a very limited scope of use for this technique - objects are not generally designed to be converted to a child type, and there is no way to enforce the logical rules that apply here. However, there may be some situation out there where this could be useful.
The attached ZIP file contains a Visual Studio 2008 solution, with projects designed to compile under the .NET 3.5 Framework. It contains a JTConvert project, which contains the applicable codefile, and a JTConvert.TestFixture project, which contains various Unit Tests designed to run in NUnit.
History
- 13th March, 2009: Initial post