Click here to Skip to main content
15,888,803 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
This question is entirely in the code below. I have a derived class that I cannot cast to its generic parent type and I don't understand why.

C#
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)}";
}


What I have tried:

I have tried reading about covariance and contravariance. I have also tried experimenting with various casts and use of the in and out generic keywords.

I have come to realise that my brain just doesn't seem to be efficiently wired for problems of this type, so please feel free to point out any complete dumbness on my part. Any help or advice will be very gratefully received.
Posted
Updated 12-May-20 0:27am
v2

1 solution

I seem to have stumbled across a solution. If I declare my ISessionState interface with the out keyword, like this...

public interface ISessionState<out S> where S : ISession


...then the compiler is happy and the cast works.

I would still very much appreciate comments on this, since I'm not sure exactly what I have done.
 
Share this answer
 
Comments
F-ES Sitecore 12-May-20 6:45am    
You can't cast t1 to ISessionState<ISession> as that isn't it's generic type, the generic type of t1 is ISessionState<SessionA> The "out" modifier means you are allowed to implicitly cast to a type that is derived from it, so as SessionA is derived from ISession adding "out" means you can cast something that is <SessionA> to <ISession>.
Patrick Skelton 12-May-20 7:08am    
Thank you for the reply. I'm still struggling to get this. I've read your reply several times and I think I see what you mean, but when you say '...you are allowed to implicitly cast to a type that is derived from it' did you mean to say '...you are allowed to implicitly cast to a type that it is derived from'?
Maciej Los 12-May-20 7:21am    
I'm pretty sure that it means exactly what you said.
In other words: ICovariant<MobilePhone> can be cast to ICovariant<Phone>.
Patrick Skelton 12-May-20 7:25am    
That is an excellent way of making it clear! I don't know why but seeing it written like that has helped a lot! Thank you. I'm still uncertain if what I am doing is inherently bad, though. I'm always wary of effectively forcing the compiler to do something it doesn't want to.
Maciej Los 12-May-20 7:30am    
You're very welcome.
I'm not an original author of above statements. I've created my own "copy" based on MSDN documentation. See: Creating Variant Generic Interfaces (C#) | Microsoft Docs[^]

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900