PositiveGuy
PositiveGuy

Reputation: 47743

Cannot convert source type to target type

I've got this subclass implementing my Interface and there are no errors in terms of satisfying the contract. However when I try to set the current session in the sub class's constructor I get this compile-time error when it tries to compare the variable type with the returned type of GetCurrentSession():

"Cannot convert source type IAPISession to target type FacebookSession"

Ok why? Facebook is a IAPISession... right??? polymorphism at play is my thinking so it should be happy with this comparison. Not sure here.

public class FacebookSession : IAPISession
{
    private FacebookSession currentSession;

    private FacebookSession()
    {
        currentSession = GetCurrentSession();
    }

    ...more code

    public IAPISession GetCurrentSession()
    {
        // my logic is here...whatever that may be
    }
     ... more code
 }

Updated

here's my actual interface:

public interface IAPISession
{
    #region Properties

    int SessionID { get; }

    string UserID { get; }

    bool SessionHasExpired { get; }

    DateTime ExpirationDate { get; }

    void LogOut(); // expires the session & sets SessionHasExpired

    #endregion Properties

    #region Methods

    IAPISession GetCurrentSession();

    #endregion Methods

}

This interface will be utilized across any API wrapper projects of ours (e.g. FlickrSession, etc.)

Upvotes: 6

Views: 12885

Answers (5)

Sanjay Manohar
Sanjay Manohar

Reputation: 7026

Yes this needs an explicit cast. You are receiving a generic (interface) session, but you want to use specific (Facebook) methods/fields.

You might envisage a scenario where GetCurrentSession() returns a different type of IAPISession!

  • use currentSession = (FacebookSession) GetCurrentSession();

  • use a try block around the cast to catch this possibility. I assume your code would get confused if it weren't a type of FacebookSession, so you need to deal with that situation.

Addition

Just to clarify:

FacebookSession fbSess;
IAPISession     genSess;
FacebookSession getFbSession() { ... return this; }
IAPISession     getSession()   { ... return this; }

genSess = getSession();        // legal
genSess = getFbSession();      // legal - implicit cast works as FacebookSession 
                               // is always a kind of IAPISession
fbSess  = getFbSession();      // legal
fbSess  = getSession();        // ILLEGAL - not all IAPISession's will be
                               // kinds of FacebookSession
fbSess  = (FacebookSession) getSession();
                               // legal, but might throw a class cast exception
                               // if it isn't a FacebookSession.

and likewise,

genSess = fbSess;              // ok, implicit cast to generic type
fbSess  = genSess;             // ILLEGAL, it may not be a FacebookSession
fbSess  = (FacebookSession) genSess; 
                               // legal but can throw an exception

Upvotes: 5

SwDevMan81
SwDevMan81

Reputation: 49978

You need the other way around:

public class FacebookSession : IAPISession
{
    private IAPISession currentSession;

    private FacebookSession()
    {
        currentSession = GetCurrentSession();
    }

    ...more code

    public FacebookSession GetCurrentSession()
    {
        // my logic is here...whatever that may be
    }
     ... more code
 }

If you want to use the specific implementation inside the class, then I would instantiate that class in the constructor. Then just return that instance in you GetCurrentSession class. For example:

public class FacebookSession : IAPISession
{
    private FacebookSession currentSession;

    private FacebookSession()
    {
        currentSession = new FacebookSession();
    }

    ...more code

    public IAPISession GetCurrentSession()
    {
        return currentSession;
    }
     ... more code
 }

And like Daniel mentions, this is getting close to the singleton pattern. See an implementation of it here. See the section under .NET Optimized Code

Upvotes: 1

James Curran
James Curran

Reputation: 103495

You must be explicit when you want to do that:

private FacebookSession() 
{ 
    currentSession = (FacebookSession) GetCurrentSession(); 
} 

Note that is will throw an exception of the object returned by GetCurrentSession() is not actually a FacebookSession.

UPDATE:

You seem to be confusing what happens at run-time with what happens at compile time:

    currentSession = GetCurrentSession(); 

This fails to compile, because, while the object returned by GetCurrentSession may be a FacebookSession object at run-time, all the compiler knows about it is that it implements IAPISession, and there could be many non-FacebookSeesion object which implement IAPISession.

    currentSession = (FacebookSession) GetCurrentSession(); 

Here you are telling the compiler, "Trust me -- when we run this, it's going be a FacebookSession object. If I'll lyin', you can crash the run with an exception!"

    currentSession = (int) GetCurrentSession(); 

This won't compile. You are trying to say "Trust me" blah-blah-blah, but the compiler calls your bluff say, "Baloney! There is no way a IAPISession can ever be an int"

Upvotes: 0

Daniel Renshaw
Daniel Renshaw

Reputation: 34177

Although GetCurrentSession might actually be returning a FacebookSession, the return type is IAPISession and there is no implicit cast from an interface to any class implementing that interface.

Either change the return type of the GetCurrentSession method to FacebookSession or change the currentSession field type to IAPISession (or both if it makes sense to do so).

Upvotes: 3

Justin Niessner
Justin Niessner

Reputation: 245399

In C#, you can't cast from a more generic type (IAPISession, in your case) to a more specific type (FacebookSession) without using an explicit cast unless there is an implict cast defined.

Think about what would happen in this case:

var flickrSession = new FlickrSession();
var iApiFlickrSession = flickrSession as IAPISession;

var faceBookSession = iApiFlickrSession;

You can be guaranteed that an instance of FacebookSession is also an instance of IAPISession but you can't always be guaranteed that an instance of IAPISession is also an instance of FacebookSession.

In that second case, the compiler wouldn't know what to do.

What you could try is using the as operator (which may or may not work in your case). The value will be null if the cast fails:

currentSession = GetCurrentSession() as FacebookSession;

Upvotes: 0

Related Questions