Charlie Malmqvist
Charlie Malmqvist

Reputation: 156

Dynamically convert object to base type

Let's say I have an object of unknown type
object obj
I can get it's base type with obj.GetType().BaseType, but how do I proceed to convert obj to this base type?

Context:

In my case, I'm writing a Serialize method which serliaizes any object to a string using reflection looking sort of like this

public static string Serialize(this object obj)
{
    string _serialization;
    foreach (field in obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
    {
        _serialization += field.value
    }
    return _serialization;
}

My problem in particular is that you can't get private fields from the base type with GetFields(), so what I want to do is to convert field.value to it's base type to be able to access those fields and recursively serialize all parent types of obj.
So what I want to be able to do is basically

foreach (baseType in field.value.baseTypes)
{
    serialization += field.value.ConvertToBaseType().Serialize()
}

All I could think of is Convert.ChangeType(object, Type) but I get an exception saying object needs to implement IConvertible, and implementing IConvertible in everything in my project is not an option. Also I suppose this method was intended for .net framework types and value types.

All code in this post is sample code used to recreate my situation as it is on a much larger scale and I can't just dump all that code here.

Edit: This is not a duplicate of that post as I have an entirely different question even if my context is similar.
There simply isn't a direct solution to my problem so I'll close this.

Upvotes: 1

Views: 828

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1499770

No, you cannot change the type of an object at execution time, nor is there any built in way of saying "Create a new object of the base type, but copy all the field values from this instance of a derived type."

But I really don't think you need to - at least not from what you've described as your reason for wanting to do so:

My problem in particular is that you can't get private fields from the base type with GetFields()

Yes you can - you just need to make sure you ask for non-public fields as well as public ones. Here's an example showing all the fields in the hierarchy, including their values for a particular instance:

using System;
using System.Reflection;

class Base
{
    private int x = 10;    
}

class Derived : Base
{
    private int y = 20;
}

class Program
{
    static void Main()
    {
        object instance = new Derived();
        var type = instance.GetType();
        while (type != null)
        {
            Console.WriteLine($"Fields in {type}:");
            var fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
            foreach (var field in fields)
            {
                Console.WriteLine($"{field.Name}: {field.GetValue(instance)}");
            }
            type = type.BaseType;
        }
    }
}

The output of this code is:

Fields in Derived:
y: 20
Fields in Base:
x: 10
Fields in System.Object:

Note that x is a private field in the base class, and yet it's still shown in the output, as desired.

So your Serialize method needs a similar loop to go through the complete class hierarchy, serializing all the fields from all the types. (I'd note that there's a lot of other complex stuff to consider in serialization, such as reference identity handling and cycles, but that's a different matter. If you can get away without writing your own serializer code, I strongly suggest you do so.)

Upvotes: 3

Aldert
Aldert

Reputation: 4313

Type tt = typeof (obj).BaseType;

foreach (FieldInfo fi in  tt.GetFields())
  {
      fi.GetValue(obj);
  }

Upvotes: 1

Related Questions