简体   繁体   中英

Why cannot I cast an object to its interface type?

I have a simple class

public class Message<T>
{
    public T Item { get; set; }

    public Message(T item)
    {
        Item = item;
    }
}

I want to create a base type BaseEvent for another set of classes, having a method ToMessage to convert to a message class like:

IConcreteEvent event = new ConcreteEvent(...);
Message<IConcreteEvent> = event.ToMessage();

Having the interface in the generic type of Message<T> is important because this object will be sent via web service.

I did something like

public interface IBaseEvent<T>
{
    Message<T> ToMessage();
}

public class BaseEvent<T> : IBaseEvent<T>
{
    public Message<T> ToMessage()
    {
        return new Message<T>((T)this); //error!
    }
}

public interface IConcreteEvent : IBaseEvent<IConcreteEvent>
{ }

public class ConcreteEvent : BaseEvent<IConcreteEvent>, IConcreteEvent
{ }

I get the error Cannot convert BaseEvent<T> to T .

I tried to force this by doing

T value = (T)Convert.ChangeType(this, typeof(T));
return new Message<T>(value);

but I get the error Object must implement IConvertible .

If I debug types I see that this is of type ConcreteEvent while typeof(T) is IConcreteEvent .

Why is the cast not working?

Finally found a solution but it took some time.

This solution is not safe : if the class ConcreteEvent don't implement its interface IConcreteEvent , you'll get a runtime InvalidCastException with message Unable to cast object of type 'ConcreteEvent' to type 'IConcreteEvent'

I also added the constraint where T : IBaseEvent<T> to the class BaseEvent<T> to better check types.

The method ToMessage can be implemented like

object value = this;
return new Message<T>((T)value);

Below a complete working example

void Main()
{
    IConcreteEvent e = new ConcreteEvent();
    Message<IConcreteEvent> msg = e.ToMessage();
}

public class Message<T>
{
    public T Item { get; set; }

    public Message(T item)
    {
        Item = item;
    }
}

public interface IBaseEvent<T>
{
    Message<T> ToMessage();
}

public class BaseEvent<T> : IBaseEvent<T>
    where T : IBaseEvent<T>
{
    public Message<T> ToMessage()
    {
        object value = this;
        return new Message<T>((T)value);
    }
}

public interface IConcreteEvent : IBaseEvent<IConcreteEvent>
{ }

public class ConcreteEvent : BaseEvent<IConcreteEvent>, IConcreteEvent
{ }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM