Spankachu
Spankachu

Reputation: 177

Casting derived class to base class keeps knowledge of derived when using generics

I have a weird scenario that I can't seem to wrap my head around. I have the following base class:

public class Note
{
    public Guid Id { get; set; }
    public string SenderId { get; set; }
    ...
}

Which is then derived by the following class:

public class NoteAttachment : Note
{
    public string FileType { get; set; }
    public string MD5 { get; set; }
    ...
}

I use these classes to communicate with a server, through a generic wrapper:

public class DataRequest<T> : DataRequest
{
    public T Data { get; set; }
}

public class DataRequest
{
    public string SomeField { get; set; }
    public string AnotherField { get; set; }
}

So I have a NoteAttachment sent to the method, but I need to wrap a Note object to send to the server. So I have the following extension method:

    public static DataRequest<T> GetDataRequest<T>(this T data)
    {
        DataRequest<T> dataRequest = new DataRequest<T>
        {
            SomeField = "Some Value",
            AnotherField = "AnotherValue",
            Data = data
        };

        return dataRequest;
    }

Now the problem. Calling the extension method in the following way works fine, however even though the DataRequest type is DataRequest<Note>, the Data field is of type NoteAttachment.

var noteAttachment = new NoteAttachment();

...

Note note = (Note)noteAttachment;

var dataRequest = note.GetDataRequest();

Debug.WriteLine(dataRequest.GetType()); //MyProject.DataRequest`1[MyProject.Note]
Debug.WriteLine(dataRequest.Data.GetType()); //MyProject.NoteAttachment <--WHY?!

What am I doing wrong?

Upvotes: 1

Views: 70

Answers (2)

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149598

As @Alexi answered your first question, ill try the second question in the comment. Add a KnownType attribute to your note class like this:

[KnownType(typeof(NoteAttachment)]
public class Note

Upvotes: 3

Alexei Levenkov
Alexei Levenkov

Reputation: 100555

You are mixing two things: run-time type of an object and compile type of a field.

Type of Data field is still Note. You can verify for yourself with reflection. For example, the following will print "Note":

Console.Write(
     typeof(DataRequest<Note>).GetProperty("Data").PropertyType.Name);

The Type of the object that this field contains can be Note or any derived type. Assigning an object to the variable of a base class does not change its run-time class. And since GetType() returns the type of an object you get the actual derived type (NoteAttachment).

Upvotes: 4

Related Questions