user5877732
user5877732

Reputation: 381

`Activator.CreateInstance` and `new` properties in derived types

I have the following classes:

public class HeaderBase
{
    public int HeaderSize { get { return sizeof(byte); } }
    public byte[] Content { get; private set; }

    public HeaderBase(byte[] bytes)
    {
        Content = bytes;
    }
}

public class BiggerHeader : HeaderBase
{
    public new int HeaderSize { get { return sizeof(byte) + sizeof(UInt32); } }

    public BiggerHeader(HeaderBase header) : base(header.Content)
    { }     
}

I also have a templated method to marshal and instantiate the BiggerHeader type

public static T Get<T>() where T : HeaderBase
{
    HeaderBase b = new HeaderBase(new byte[]{});
    T instance = (T)Activator.CreateInstance(typeof(T), b);
    return instance;
}

According to MSDN:

where T : <base class name>: The type argument must be or derive from the specified base class.

However, the value of HeaderSize is 1 and not 5 as I would have expected. Why would this be the case, and how can I instantiate an object which will use the new properties from derived types?

DotNetFiddle

Related: Generics in C# - how can I create an instance of a variable type with an argument?

Upvotes: 2

Views: 623

Answers (2)

usr
usr

Reputation: 171178

new members have the same name as a base member but are otherwise unrelated. It looks like you want to make use of virtual in the base and override in the derived class.

With new you essentially silenced the warning that warned you about this. new had no functional effect.

Calls on T are resolved as if T was HeaderBase. Anything else would require the runtime to perform a dynamic binding at runtime based on the name of what you called. Imagine T t; t.Xyz();. That code would not compile because no Xyz was found statically. But you are doing the same thing! At the time of compiling the method there is no Derived.HeaderSize visible because we don't know that T is going to be Derived. It could end up being something else. That's why the call is statically bound to Base.HS. The fact that B.HS and D.HS have the same name means nothing. It's a coincidence.

Upvotes: 3

Fabjan
Fabjan

Reputation: 13676

Well, I believe that mainly error here is a result of bad architecture.

Let's add some improvements and make all properties, that has to be changed in every other derived class - abstract. By doing so we'll make sure that we didn't forget anything, and can start using polymorphism (override behaviour).

Let's also use some features of C# 6.0

It'll also make code more readable :

public abstract class AbstractHeader
{
    public abstract int HeaderSize { get; }
    public virtual byte[] Content { get; set; }

    protected AbstractHeader() { }

    protected AbstractHeader(byte[] bytes)
    {
        Content = bytes;
    }
}

public class BaseHeader : AbstractHeader
{
    public override int HeaderSize => sizeof (byte);
}

public class BiggerHeader : AbstractHeader
{
    public override int HeaderSize => sizeof (byte) + sizeof (UInt32);

    public BiggerHeader(BaseHeader header) : base(header.Content)
    {
    }
}

Upvotes: 1

Related Questions