Click here to Skip to main content
15,118,713 members
Articles / Programming Languages / C#
Posted 28 Mar 2017

Tagged as


7 bookmarked

C# Initialize Class with Instance of Its Base

Rate me:
Please Sign up or sign in to vote.
2.97/5 (10 votes)
1 Apr 2017CPOL3 min read
How to automatically initialize a class for an inherited class instance


Imagine an existing project which uses classes that simply represent database tables. There is no relation between the classes and you have to manually find and handle sub-classes including their reference tables.

I recently had such a project and quickly got a headache because I couldn't change the existing project but had to write a tool to crawl though some data of it. Instead of using SQL in every single part of the project to combine the structure, I wanted to have that in one place so I wrote wrapper classes.

And that's where my problems began...


Casting in C# works in one direction only: You can case an instance of a class in any inherited class - no matter how nested it is - up to being an object:

public class Fruit {
    public float Sugar { get; set; }
    public int Size { get; set; }
public class Apple : Fruit {
    public int NumberOfWorms { get; set; }

Apple a = new Apple() { Sugar = 5.0f, Size = 10, NumberOfWorms = 0 }

TreeFruit tf = (TreeFruit)a;
Fruit f = (Fruit)a;
object o = (object)a;

Now the way to check this, is to ask if every instance of A is a B, then you can cast it. E.g. every Apple is a Fruit so you can cast an Apple into a Fruit. But not every Fruit is an Apple so you cannot cast a Fruit in an Apple.

At this point, it gets a bit nasty to explain, because a Fruit can only have properties every Apple will have too. So why is it not possible to just instantiate an Apple with a Fruit instance that fills all Fruit properties of the apple? I'm thinking of doing something like this - which of course doesn't work:

public class Apple : Fruit {
    public int NumberOfWorms { get; set; }
    public Apple(Fruit fruit, int noOfWorms) { 
        base = fruit; // <- nope! Not allowed!
        this.NumberOfWorms = noOfWorms;

Now you can of course manually copy all properties like this:

public class Apple : Fruit {
    public int NumberOfWorms { get; set; }
    public Apple(Fruit fruit, int noOfWorms) { 
        this.Sugar = fruit.Sugar;
        this.Size = fruit.Size;
        this.NumberOfWorms = noOfWorms;

But this can quickly evolve into a whole load of work and regarding the maintenance of the code, this is a nightmare because every time the base class changes, the inheriting classes have to be adjusted too - and if you just add a property to the base class, it'll not even show up as a compiling error and produces hard to find bugs somewhere completely unrelated.

Using the Code

My solution to this is a helper method that can be called in the constructor of an inheriting class just to do the work by looking up the base's properties via Reflection and then copy them over to the inheriting instance.

using System;
using System.Reflection;

namespace BjSTools.Helpers {
    public static class InheritHelper {
        public static void FillProperties<T, Tbase>(this T target, Tbase baseInstance) 
        where T : Tbase {
            Type t = typeof(T);
            Type tb = typeof(Tbase);
            PropertyInfo[] properties = tb.GetProperties();
            foreach (PropertyInfo pi in properties) {
                // Skip unreadable and writeprotected ones
                if (!pi.CanRead || !pi.CanWrite) continue;
                // Read value
                object value = pi.GetValue(baseInstance, null);
                // Get Property of target class
                PropertyInfo pi_target = t.GetProperty(pi.Name);
                // Write value to target
                pi_target.SetValue(target, value, null);

It's an extension method so to use it, you just need to add a using line and call the extension method on yourself:

using System;
// Here comes the using line:
using BjSTools.Helpers;

namespace TestArea {
    public class Apple : Fruit {
        public int NumberOfWorms { get; set; }

        // New constructor
        public Apple(Fruit fruit, int noOfWorms) {
            // This copies all the properties from fruit to this instance
            // Now we can take care of the new properties
            this.NumberOfWorms = noOfWorms;

And it works like a charm.

Points of Interest

I use Reflection here. There are many people out there rejecting the use of Reflection because it is indeed slower than manual mapping. You'll have to choose yourself rather your priority is speed or coding efford.

Note that I explicitly look for the PropertyInfo of the inheriting type instead of using the base PropertyInfo twice. This is because otherwise overrides would not work when calling the base property.

Also note that this method is explicitly limited to work on instances with their base type. You can delete the where statement of the method definition to eliminate this limitation but be aware that you should add additional checks if the target properties are available and if their type is the same because without the limitation, you can copy any properties of any instance to any instance of a completely different class.

And yet another note: The method copies reference values by reference! So if a List<> is copied, it's the same one in the target and the base instance and if you change one, the other is changed as well.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer
Germany Germany
I'm working mainly on .NET Compact Framework C# on mobile devices at work. At home it's .NET Full Framework C# and a bit JavaScript.

Comments and Discussions

QuestionYour way is cool, but evil Pin
Maximys1-Apr-17 7:23
MemberMaximys1-Apr-17 7:23 
AnswerRe: Your way is cool, but evil Pin
Bjørn3-Apr-17 22:45
MemberBjørn3-Apr-17 22:45 
SuggestionThe OOP way Pin
Midi_Mick1-Apr-17 5:19
professionalMidi_Mick1-Apr-17 5:19 
GeneralRe: The OOP way Pin
Bjørn1-Apr-17 5:35
MemberBjørn1-Apr-17 5:35 
QuestionHas its Place Pin
RandyBuchholz30-Mar-17 18:38
MemberRandyBuchholz30-Mar-17 18:38 
PraiseThanks! Pin
Jim Meadors29-Mar-17 19:58
MemberJim Meadors29-Mar-17 19:58 
QuestionSorry, too many issues Pin
wkempf28-Mar-17 8:27
Memberwkempf28-Mar-17 8:27 
GeneralRe: Sorry, too many issues Pin
David Rush28-Mar-17 10:23
professionalDavid Rush28-Mar-17 10:23 
GeneralRe: Sorry, too many issues Pin
wkempf29-Mar-17 2:46
Memberwkempf29-Mar-17 2:46 
GeneralRe: Sorry, too many issues Pin
David Rush29-Mar-17 7:21
professionalDavid Rush29-Mar-17 7:21 
GeneralRe: Sorry, too many issues Pin
Bjørn30-Mar-17 1:54
MemberBjørn30-Mar-17 1:54 
Hello together and thank you for your feedback.

I want to note that this is a community and thus the guidelines on how you're supposed do things vary from individual to individual. I've been told on several occasions that first the code must be downloadable and second that you're not supposed to repeat it in the article, so I uploaded it as file - which by the way can simply be browsed with CodeProject's automatic tool "Browse Code" at the upper left of the article.

Yes, I do use Reflection and I write so in my text plus I even added a tag for it. Reflection definitely reduces performance but it can also massively shorten coding time. When looking at it that way, C# itself is a trade between usability and performance. In my case the performance doesn't matter as the whole task took my computer about three minutes to complete and even though it might have been faster with static allocation, me writing that allocation would have taken longer than the whole processing.

David Rush you pointed out the situation correctly. I'm working with proprietary code which I wasn't allowed to change but had to use - and I'm also not allowed to post any of that code here.

This article is a tip/trick that is meant to share my solution with people in a similar situations and I agree that I could have done a better example. I just couldn't afford to put more time in it and found that for someone in need of such a solution this would be enough.
( . .)
c(")(") NeoBurn

AnswerRe: Sorry, too many issues Pin
Bernhard Hiller31-Mar-17 3:56
MemberBernhard Hiller31-Mar-17 3:56 
QuestionRe: Sorry, too many issues Pin
Bjørn1-Apr-17 5:08
MemberBjørn1-Apr-17 5:08 
AnswerRe: Sorry, too many issues Pin
Bernhard Hiller2-Apr-17 22:03
MemberBernhard Hiller2-Apr-17 22:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.