Reputation: 47743
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
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.
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
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
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
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
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