Patrick Skelton Ответов: 1

Как привести производный класс к его универсальному родительскому типу?


Этот вопрос полностью содержится в приведенном ниже коде. У меня есть производный класс, который я не могу привести к его универсальному родительскому типу, и я не понимаю, почему.

public interface ISession {}

public abstract class SessionBase : ISession, IEnumerable<ISessionState<ISession>>
{
    public List<ISessionState<ISession>> SessionStates = new List<ISessionState<ISession>>();

    public IEnumerator<ISessionState<ISession>> GetEnumerator() => SessionStates.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => SessionStates.GetEnumerator();

    public void RunStateMethod()
    {
        Console.WriteLine( SessionStates[ 0 ].SomeMethod() );
    }
}

public class SessionA : SessionBase
{
    public SessionA()
    {
        var t1 = new SessionAState( this );
        var t2 = t1 as ISessionState<ISession>; // t2 is null
        SessionStates.Add( t2 );
    }
}

public interface ISessionState<S> where S : ISession
{
    string SomeMethod();
}

public abstract class SessionStateBase<S> : ISessionState<S> where S : ISession
{
    public SessionStateBase( S session ) { Session = session; }

    public ISession Session { get; } = null;

    public abstract string SomeMethod();
}

public class SessionAState : SessionStateBase<SessionA>
{
    public SessionAState( SessionA session ) : base( session ) {}

    public override string SomeMethod() => $"Some method in {nameof(SessionAState)}";
}


Что я уже пробовал:

Я пробовал читать о ковариации и контравариантности. Я также пробовал экспериментировать с различными слепками и использованием в и из общие ключевые слова.

Я пришел к пониманию, что мой мозг просто не способен эффективно решать проблемы такого рода, поэтому, пожалуйста, не стесняйтесь указывать на любую полную тупость с моей стороны. Любая помощь или совет будут приняты с большой благодарностью.

1 Ответов

Рейтинг:
1

Patrick Skelton

Кажется, я наткнулся на решение. Если я объявлю свое ISessionState интерфейс с out ключевое слово, вот так...

public interface ISessionState<out S> where S : ISession


..тогда компилятор доволен, и актерский состав работает.

Я все еще был бы очень признателен за комментарии по этому поводу, поскольку я не уверен точно, что я сделал.


F-ES Sitecore

Вы не можете разыграть T1 до ISessionState&ЛТ;ISession и GT; как это не это родовой тип, родовой тип Т1 ISessionState&ЛТ;Сессииа&ГТ; на "выход" модификатор означает, что вам разрешено неявное приведение к типу, производный от него, так как Сессииа является производным от ISession добавления "вне" означает, что вы можете бросить то, что &ЛТ;Сессииа и GT; к <ISession&ГТ;.

Patrick Skelton

Спасибо за ответ. Я все еще борется, чтобы получить это. Я несколько раз читал ваш ответ и, кажется, понимаю, что вы имеете в виду, но когда вы говорите ... ..вы можете неявно привести к типу, который является производным от него "вы хотели сказать"...вам разрешено неявно приводить к типу, из которого он является производным'?

Maciej Los

Я почти уверен, что это означает именно то, что вы сказали.
Иначе говоря: ICovariant<MobilePhone> может быть брошен в ICovariant<Phone>.

Patrick Skelton

Это отличный способ прояснить ситуацию! Я не знаю почему, но видеть, как это написано, очень помогло! Спасибо. Однако я все еще не уверен, что то, что я делаю, изначально плохо. Я всегда опасаюсь эффективно заставлять компилятор делать то, что он не хочет.

Maciej Los

Всегда пожалуйста.
Я не являюсь оригинальным автором вышеприведенных утверждений. Я создал свою собственную "копию" на основе документации MSDN. Видеть: Создание Вариантов Универсальных Интерфейсов (C#) | Microsoft Docs[^]