I\'m trying to do some unit testing on a project that unfortunately has high level of unit interdependence. Currently, a lot of our classes look to a custom UserId
as does not invoke conversion operators. See: http://msdn.microsoft.com/en-us/library/cscsdfbt(v=VS.100).aspx
Use a (cast).
Does the fact that I have my Identity (in Foo) defined as IIdentity somehow prevent resolution of the cast using the explicit operators of the implementing type?
Here's a hint: how do you define an explicit (or implicit, for that matter) conversion operator? (I know you know this since you already did it; I am asking the question to illustrate a point.)
public static explicit operator UserIdentity(MockUserIdentity src)
{
return src.UserIdentity;
}
There's something very important to realize here. The C# designers made the wise choice of making all operators static. So the explicit operator defined above translates to essentially a static method call looking something like this:
public static UserIdentity op_Explicit(MockUserIdentity src)
{
return src.UserIdentity;
}
Now, here is what I'm getting at. The behavior that perplexed you in your question because it seemed to fail in the polymorphism department was really the result of C#'s system of method overload resolution.
If I have two methods:
void Write(string s) { Console.WriteLine("string"); }
void Write(object o) { Console.WriteLine("object"); }
...and then I have this program:
object x = "Hello!";
Write(x);
What will the output be?
The answer is "object" because the Write(object)
overload was selected by the compiler -- as well it should have been. Write
is not an instance method to be overridden by some derived type according to normal polymorphism; it is a static method, with overloads between which the compiler must make a choice. Since x
in the above code is declared to be of type object
, that choice is unambiguously Write(object)
.
So in the case of your code, where you have this:
public IIdentity Identity { get; set; }
public CoreIdentity GetCoreIdentity()
{
return (CoreIdentity)Identity;
}
The compiler must investigate: is there an op_Explicit
overload which accepts an IIdentity
parameter? No, there is not. There's one that accepts a UserIdentity
parameter, but that's too specific (just as Write(string)
was too specific for x
in the example above).
So the reason your explicit operator was not called in your initial tests was that the compiler will not resolve (CoreIdentity)Identity
to that particular overload. This is also why your modified version does work:
public CoreIdentity GetCoreIdentity()
{
ExtendedIdentity exId = Identity as ExtendedIdentity;
if (exId != null)
{
// Since exId is actually declared to be of type ExtendedIdentity,
// the compiler can choose the operator overload accepting
// an ExtendedIdentity parameter -- so this will work.
return (CoreIdentity)exId;
}
return (CoreIdentity)Identity;
}
As mentioned by Ray as
doesn't invoke the conversion operators.
That said, you should be using an explicit cast in that type of scenarios.
That way, You get very clear information when something isn't set up right and the object at ApplicationContext.User.Identity wasn't what the code expected it to.
So, why don't you use an explicit cast?
// will throw if cast fails
internal static UserIdentity GetCurrentIdentity()
{
UserIdentity currentIdentity = (UserIdentity) ApplicationContext.User.Identity ;
return currentIdentity;
}
This ought to trigger your explicit operator. You can test with is
first to make it safer.