Implicit / Explicit Conversion for the How keyword

I am trying to run some unit tests for a project that, unfortunately, has a high level of block interdependence. Currently, many of our classes refer to the UserIdentity user object to define authentication, but this object has many internal hoops that I would just as quickly avoid when trying to test individual module functionality.

To get around some of this, I am trying to create a โ€œmockโ€ version of this UserIdentity that can be connected to a more rigid controlled environment.

In short, we have a UserIdentity class with several read-only public properties and a static CurrentIdentity ( IIdentity ) tag. I can get around almost everything using the IIdentity โ€œlayoutโ€, but I run into a wall when I reach the point at which CurrentIdentity is used as UserIdentity .

This is a pretty simple method:

internal static UserIdentity GetCurrentIdentity() { UserIdentity currentIdentity = ApplicationContext.User.Identity as UserIdentity; return currentIdentity; } 

I set my layout to create a member of type UserIdentity and then do something like this:

  public static implicit operator UserIdentity(MockUserIdentity src) { return src.UserIdentity; } 

or

  public static explicit operator UserIdentity(MockUserIdentity src) { return src.UserIdentity; } 

The problem is that, as far as I can tell, the โ€œhowโ€ does not seem to cause an explicit or explicit conversion operation on my layout object. My question is (is it?), I missed something simple here or it wonโ€™t work, because (as I assume) the โ€œhowโ€ operation looks directly at the class inheritance (which my object does not ...)?

In addition, maybe a little from the topic, but why in the same class cannot be both explicit and implicit operators of the same resulting type? If I miss something stupid, the compiler stops working if I try to use both conversion operators at the same time. I have to choose one or the other.

UPDATE

OK, now I'm completely confused. Maybe I'm getting sloppy, but I tried to do direct casting, and I can't get it to work. I read the statement on MSDN, and this example shows the statement going in the resulting class, not the source class, but I'm not sure if it matters or not (I tried both places in the code below). In any case, I tried to create a simple test bed in order to understand what I can do wrong, but I can not make it work ... That's what I have

 class Program { // Shared Interface public interface IIdentity { } // "real" class (not conducive to inheritence) public class CoreIdentity : IIdentity { internal CoreIdentity() { } // Just in case (if this has to be here, that seems unfortunate) public static explicit operator CoreIdentity(ExtendedIdentity src) { return src.Identity; } } // "mock" class (Wraps core object) public class ExtendedIdentity : IIdentity { public CoreIdentity Identity { get; set; } public ExtendedIdentity() { Identity = new CoreIdentity(); } // This is where the operator seems like it should belong... public static explicit operator CoreIdentity(ExtendedIdentity src) { return src.Identity; } } // Dummy class to obtain "current core identity" public class Foo { public IIdentity Identity { get; set; } public CoreIdentity GetCoreIdentity() { return (CoreIdentity)Identity; } } static void Main(string[] args) { ExtendedIdentity identity = new ExtendedIdentity(); Foo foo = new Foo(); foo.Identity = identity; CoreIdentity core = foo.GetCoreIdentity(); } } 

But this throws the following exception when I call foo.GetCoreIdentity ():

Cannot pass an object of type "ExtendedIdentity" to enter "CoreIdentity".

and I can't catch any of my explicit operators with a breakpoint, so it looks like he is making this definition without even โ€œtryingโ€ the conversion routes that I provided.

Of course, I miss something obvious. Does the fact that I have my Identity (in Foo), defined as IIdentity, somehow prevent the resolution of the cast using explicit operators like implementation? It would seem strange to me.

UPDATE (# 2)

It seems to me that I am sending out my post with all these updates (maybe I need to reduce my actions before they are happy with the trigger :)) Anyway, I changed my Foo GetCoreIdentityMethod to do this instead:

 public CoreIdentity GetCoreIdentity() { ExtendedIdentity exId = Identity as ExtendedIdentity; if (exId != null) return (CoreIdentity)exId; return (CoreIdentity)Identity; } 

and (after clearing the ambiguous reference caused by the presence of an operator in both classes), he took a step in my explicit code for the conversion operator, and it worked as expected. So, I think it seems that explicit operators are not resolved polymorphically (is this the correct understanding?), And the fact that my property was entered as an identifier and not ExtendedIdentity did not allow it to refer to cast logic, even if it was an ExtendedIdentity Type at the time of his call. It strikes me as very peculiar and unexpected ... and kind of miserable.

I do not want to rewrite the keeper of the CurrentIdentity object so that it knows about my special test cast mocks. I wanted to encapsulate this โ€œspecialโ€ logic in the layout itself, so it really throws me into a loop.

+4
source share
4 answers

since it does not call conversion operators. See: http://msdn.microsoft.com/en-us/library/cscsdfbt(v=VS.100).aspx

Use (cast).

+3
source

Does the fact that I have my identity (in Foo) is defined as IIdentity to somehow prevent the explicit operators from implementing the type to resolve?

Here's a tip: how do you define an explicit (or implicit, for that matter) conversion operator? (I know that you know this, since you have already done this, I ask a question to illustrate the point.)

 public static explicit operator UserIdentity(MockUserIdentity src) { return src.UserIdentity; } 

There is something very important here. C # designers made the right choice for all static statements. Thus, the explicit operator defined above translates essentially a call to a static method that looks something like this:

 public static UserIdentity op_Explicit(MockUserIdentity src) { return src.UserIdentity; } 

Now, here is what I get. The behavior that puzzled you in your question because it seems to have failed in the polymorphism department was really the result of the C # system to allow method overloading.

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 be the way out?

The answer is "object" because the compiler chose Write(object) overload, as you would expect. Write not an instance method that must be overridden by some derived type in accordance with ordinary polymorphism; it is a static method with overloads between which the compiler must make a choice. Since x in the above code is declared as an object type, this choice is uniquely Write(object) .

So, in the case of your code, where do you have this:

 public IIdentity Identity { get; set; } public CoreIdentity GetCoreIdentity() { return (CoreIdentity)Identity; } 

The compiler should investigate: is there an op_Explicit overload that takes an IIdentity parameter? No no. There is one that takes a UserIdentity parameter, but is too specific (just like Write(string) was too specific for x in the above example).

So, the reason your explicit statement was not called in your initial tests was because the compiler would not allow (CoreIdentity)Identity for this particular overload. This is why your modified version works:

 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; } 
+5
source

So why not use an explicit listing?

 // will throw if cast fails internal static UserIdentity GetCurrentIdentity() { UserIdentity currentIdentity = (UserIdentity) ApplicationContext.User.Identity ; return currentIdentity; } 

This should call your explicit statement. You can check is first to make it more secure.

+1
source

As already mentioned, Ray as does not call conversion operators.

However, you must use an explicit cast in this type of script.

This way you get very clear information if something is not configured correctly and the object in ApplicationContext.User.Identity was not what the code expected.

0
source

All Articles