User-defined conversion operator from base class

前端 未结 11 1500
南旧
南旧 2020-12-01 02:40

Introduction

I am aware that \"user-defined conversions to or from a base class are not allowed\". MSDN gives, as an explanation to this rule, \"You

相关标签:
11条回答
  • 2020-12-01 03:15

    It seems the reference equality was not your concern, then you can say:

    • Code

      public class Entity {
          public sealed class To<U> where U : Entity {
              public static implicit operator To<U>(Entity entity) {
                  return new To<U> { m_handle=entity.Pointer };
              }
      
              public static implicit operator U(To<U> x) {
                  return (U)Activator.CreateInstance(typeof(U), x.m_handle);
              }
      
              To() { // not exposed
              }
      
              IntPtr m_handle; // not exposed
          }
      
          IntPtr Pointer; // not exposed
      
          public Entity(IntPtr pointer) {
              this.Pointer=pointer;
          }
      }
      

      public class Body:Entity {
          public Body(IntPtr pointer) : base(pointer) {
          }
      }
      
      // added for the extra demonstration
      public class Context:Body {
          public Context(IntPtr pointer) : base(pointer) {
          }
      }
      

    and the

    • Test

      public static class TestClass {
          public static void TestMethod() {
              Entity entity = new Entity((IntPtr)0x1234);
              Body body = (Entity.To<Body>)entity;
              Context context = (Body.To<Context>)body;
          }
      }
      

    You didn't write the accessors but I took the encapsulation into account, to not expose their pointers. Under the hood of this implementation is use an intermediate class which is not in the inheritance chain but chain the conversion.

    Activator involved here is good for not adding extra new() constraint as U are already constrained to Entity and have a parameterized constructor. To<U> though is exposed but sealed without exposing its constructor, it can only be instantiated from the conversion operator.

    In the test code, the entity actually converted to a generic To<U> object and then the target type, so is the extra demonstration from body to context. Because To<U> is a nested class, it can access the private Pointer of the containing class, thus we can accomplish things without exposing the pointer.

    Well, that's it.

    0 讨论(0)
  • 2020-12-01 03:16

    How about:

    public class Entity {...}
    
    public class Body : Entity
    {
      public Body(Entity sourceEntity) { this.Pointer = sourceEntity.Pointer; }
    }
    

    so in code you don't have to write:

    Body someBody = new Body(previouslyUnknownEntity.Pointer);
    

    but you can use

    Body someBody = new Body(previouslyUnknownEntity);
    

    instead.

    It's just a cosmetic change, I know, but it is pretty clear and you can change the internals easily. It's also used in a wrapper pattern that I can't remember a name of (for slightly diff. purposes).
    It's also clear you are creating a new entity from a provided one so should not be confusing as an operator/conversion would be.

    Note: haven't used a compiler so possibility of a typo is there.

    0 讨论(0)
  • 2020-12-01 03:17

    You should use your Solution B (the constructor argument); firstly, here's why not to use the other proposed solutions:

    • Solution A is merely a wrapper for Solution B;
    • Solution C is just wrong (why should a base class know how to convert itself to any subclass?)

    Also, if the Body class were to contain additional properties, what should these be initialized to when you perform your cast? It's far better to use the constructor and initialize the subclass's properties as is convention in OO languages.

    0 讨论(0)
  • 2020-12-01 03:19

    It is an old discussion, though, but I just wanted to add some experiences of my own.

    In a class library, we had once mathematical objects like 2D points AND 2D vectors. Because the features of the objects of both classes are mostly the same (although not quite the same, wherefore both classes were needed), the idea was to define a Vector2D and to derive Point2D from it. It would spare a lot of repeating definitions, but a custom conversion operator from vector to point would not be possible.

    So since we strongly wanted to deliberately exchange the types in the code, we just decided to give up the idea of derivation, declared both classes independently and introduced implicit conversion operators. Then we could freely exchange both types in the code.

    0 讨论(0)
  • 2020-12-01 03:21

    Honestly, I think the original request is being misunderstood.

    Consider the simple situation where a base class is just serving as a grouping of related classes.

    Ex:

    class Parent ...
    class Child1 : Parent ...
    class Child2 : Parent ...
    

    Where the programmer knows how to explicitly convert from one child class to another.

    The Parent class can be used, for example, in:

    Dictionary<string, Parent>
    

    What I think the original request is asking for is:

    How to be able to code:

    Class1 v1 = ...
    Class2 v2 = ...
    
    v1 = v2;
    

    Where inside Parent there is explicit code to do the conversion from Class2 to Class1 objects.

    I have this exact situation in my code.

    The best I managed to do was to add a property to Parent class that knows how to do the conversion and returns the proper typed object.

    This forces me to write my code:

    v1 = v2.AsClass1;

    Where the property AsClass1 in Parent knows how to do the actual conversion from Class2 to Class1.

    Honestly this is a code kludge (its ugly; detracts from from simplicity, can make expressions ridiculously long, obfuscates, and most annoyingly it lacks elegance) but its the best I could come up with.

    And, yes, you guessed it, the Parent class also includes the AsClass2 method :-)

    All I wanted to do was:

    v1 = v2;
    

    and have the compiler silently invoke the method I specified to do the conversion.

    I really don't understand why the compiler does support this :-(

    In my mind this is really no different then:

    int v1;
    decimal v2;
    . . .
    v1 = (int)v2;
    

    The compiler knows to silently invoke some built-in conversion method.

    0 讨论(0)
提交回复
热议问题