Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Downcast" an object to its base type in C#

I'm still working on my general-purpose logging component which should handle any kind of an object and convert it ("serialize" it) to a string.

Works quite well so far - except for one requirement: I should be able to identify the base type of a given object (if one exists), and also list that base type's properties separately.

Basically, I have a method something like this:

public string LogObject(object myObject)

and now I'd like to check to see if this object's type has a base class, and if so - get the properties of my object, "downcast" to its base type.

The checking of the base type isn't hard:

Type baseType = myObject.GetType().BaseType;

but how do I downcast myObject to an object of type baseType now?

I tried several things, like:

object baseObject = Convert.ChangeType(myObject, baseType);

but that requires my object type to implement IConvertible which I cannot possible require from all my objects...

Any other way?

Those of course don't work....

object baseObject = myObject as baseType;
object baseObject = (baseType)myObject;

Any other way I'm not thinking of?

Update: I had already thought about doing it by

  • grabbing all the properties of myObject into allProperties
  • grabbing just those properties declared on the myObject type into declaredProperties (BindingFlag.Declared)
  • getting the baseProperties by subtracting the declaredProperties from allProperties

but that just seems a bit excessive on the reflection - not sure if that'll perform decently....

like image 211
marc_s Avatar asked May 14 '13 21:05

marc_s


People also ask

What is downcasting in C?

In class-based programming, downcasting or type refinement is the act of casting a reference of a base class to one of its derived classes.

What is used for downcasting base class pointers?

A dynamic cast expression is used to cast a base class pointer to a derived class pointer. This is referred to as downcasting.

Why downcasting is not allowed?

Downcasting is not allowed without an explicit type cast. The reason for this restriction is that the is-a relationship is not, in most of the cases, symmetric. A derived class could add new data members, and the class member functions that used these data members wouldn't apply to the base class.

Can you downcast with Static_cast?

The C++ built-in static_cast can be used for efficiently downcasting pointers to polymorphic objects, but provides no error detection for the case where the pointer being cast actually points to the wrong derived class.


2 Answers

Use BindingFlags.DeclaredOnly to get members declared on a specific type only. Also, even if you do not use this flag, every returned ProperyInfo has a DeclaredType property which lists the type declaring the property.

The only reason I can think of for using DeclaredOnly is if you want better control over the result set, e.g. to filter out virtual properties that have been overridden in subclasses.

PS: Using a library like Fasterflect can make tasks like this a breeze ;)

like image 91
Morten Mertner Avatar answered Sep 19 '22 09:09

Morten Mertner


Solution:

If anyone is interested - based on Oded's and Morten's comments, this is the solution I ended up using:

// get all the properties of "myObject"
List<PropertyInfo> propertyInfoList = new List<PropertyInfo>(myObject.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public));

// get the object's type and its base type
Type objectType = objectToLog.GetType();
Type baseType = objectToLog.GetType().BaseType;

// if a baseType exists ...
if (baseType != null)
{
    // get the list of properties that are *not* defined directly in "myObject" - 
    // those are all the properties defined in the immediate and possible other base types
    List<PropertyInfo> baseProperties = propertyInfoList.Where(x => x.DeclaringType != objectType).ToList();

    // process those base properties

    // after processing, remove the base properties from the list of "all" properties to get just those
    // properties that are defined directly on the "myObject" type

    List<PropertyInfo> declaredProperties = propertyInfoList.Except(baseProperties);        
}
like image 37
marc_s Avatar answered Sep 20 '22 09:09

marc_s