1

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.

  • Possible duplicate of [Reflecting a private field from a base class](https://stackoverflow.com/questions/6961781/reflecting-a-private-field-from-a-base-class) – Etienne de Martel Aug 17 '18 at 18:50
  • I need to **dynamically** go up the inheritance chain not **manually** like the answers for that post suggests and which the poster accepted. – Charlie Malmqvist Aug 17 '18 at 18:56
  • @CharlieMalmqvist: So you call `BaseType` dynamically, as many times as you need to, as shown in my answer. It doesn't help that you've only shown us pseudo-code. If you could provide a [mcve] (as my answer does) it would be easier to help you. – Jon Skeet Aug 17 '18 at 19:00

2 Answers2

2

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.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • No this does not get the private fields in `Base`, only private fields int `Derived`. – Charlie Malmqvist Aug 17 '18 at 18:41
  • @CharlieMalmqvist: What's the output when you run my code? For me it's "Fields in Derived: y: 20 Fields in Base: x: 10 Fields in System.Object:" - which shows it *does* give fields in the base class. – Jon Skeet Aug 17 '18 at 18:57
  • @CharlieMalmqvist: I've added the "No, you can't change the type of an object" bit at the start of the answer, but I'm not sure why you're so reluctant to accept that you don't need to anyway, and that your original reason for wanting to do so isn't actually a problem. Do you have some *other* reason why you think you need to do this? – Jon Skeet Aug 17 '18 at 19:28
  • I no longer need this my problem is solved thanks for the help. – Charlie Malmqvist Aug 17 '18 at 21:14
1
Type tt = typeof (obj).BaseType;

foreach (FieldInfo fi in  tt.GetFields())
  {
      fi.GetValue(obj);
  }
Aldert
  • 4,209
  • 1
  • 9
  • 23
  • Okay, and now to my question - how do I convert `obj` to the type of `tt`? – Charlie Malmqvist Aug 17 '18 at 18:38
  • @CharlieMalmqvist: You don't - you just ask for the fields from the base type, and get their values from `obj`. My answer gives a complete example of that. – Jon Skeet Aug 17 '18 at 18:41
  • You're right but that doesn't answer my question. I need to be able to make that conversion for my method to work due to the way I've done it this far. However if noone comes with a solution for that I will accept this as an answer. – Charlie Malmqvist Aug 17 '18 at 18:53
  • @CharlieMalmqvist: There's no way of making such a conversion, and doing so would be utterly infeasible in some cases - what would you expect to happen if the base class were abstract, for example? You can't have an object whose type is an abstract class. But as I've said on my answer, you *can* get the fields of the base type this way - as my answer and its output show. – Jon Skeet Aug 17 '18 at 18:58
  • I don't think it would be _utterly infeasible _, if the base class was abstract it would simply throw an exception just like `Activator.CreateInstace()` does when you try to create an instance of an abstract type. Anyways, then this means there isn't really a solution to my problem. Thanks anyway. – Charlie Malmqvist Aug 17 '18 at 19:06
  • @CharlieMalmqvist: You say the problem is that you can't access private fields in the base type - but you absolutely can. You can't change the type of an object, but again, I really don't think you need to - you certainly haven't made it clear *why* you think you need to, other than because of a perceived limitation which doesn't actually exist. – Jon Skeet Aug 17 '18 at 19:12
  • My question is if you can convert and object to it's base type dynamically, the answer is no. I'll end it there, I don't need any further help. Add that to your posted answer on the top so I can mark it as an answer. – Charlie Malmqvist Aug 17 '18 at 19:15