Почему я не могу привести объект к типу интерфейса? - PullRequest
0 голосов
/ 13 марта 2020

У меня есть простой класс

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

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

Я хочу создать базовый тип BaseEvent для другого набора классов, имея метод ToMessage для преобразования в класс сообщений, например:

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

Наличие интерфейса в обобщенном c типе Message<T> важно, потому что этот объект будет отправлен через веб-сервис.

Я сделал что-то вроде

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
{ }

Я получаю ошибку Cannot convert BaseEvent<T> to T.

Я пытался форсировать это, выполняя

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

, но я получаю ошибку Object must implement IConvertible.

Если я отлаживаю типы, я вижу, что this имеет тип ConcreteEvent, а typeof(T) - IConcreteEvent.

Почему не работает приведение?

1 Ответ

0 голосов
/ 13 марта 2020

Наконец-то нашли решение, но это заняло некоторое время.

Это решение небезопасно : если класс ConcreteEvent не реализует свой интерфейс IConcreteEvent, вы будете получить время выполнения InvalidCastException с сообщением Unable to cast object of type 'ConcreteEvent' to type 'IConcreteEvent'

Я также добавил ограничение where T : IBaseEvent<T> к классу BaseEvent<T> для лучшей проверки типов.

Может быть реализован метод ToMessage как

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

Ниже полный рабочий пример

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
{ }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...