User-defined conversion operator from base class

C#Casting

C# Problem Overview


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 do not need this operator."

I do understand that an user-defined conversion to a base class is not needed, as this obviously done implicitly. However, I do need a conversion from a base class.

In my current design, a wrapper of unmanaged code, I use a pointer, stored in an Entity class. All the classes using a pointer derive from that Entity class, for example, a Body class.

I therefore have:

Method A

class Entity
{
    IntPtr Pointer;

    Entity(IntPtr pointer)
    {
        this.Pointer = pointer;
    }
}

class Body : Entity
{
    Body(IntPtr pointer) : base(pointer) { }

    explicit operator Body(Entity e)
    {
        return new Body(e.Pointer);
    }
}

This cast is the illegal one. (Note that I didn't bother writing the accessors). Without it, the compiler will allow me to do:

Method B

(Body)myEntity
...

However, at runtime, I will get an exception saying this cast is impossible.

Conclusion

Therefore here I am, needing an user-defined conversion from a base class, and C# refuses it to me. Using method A, the compiler will complain but the code would logically work at runtime. Using method B, the compiler will not complain but the code will obviously fail at runtime.

What I find strange in this situation is that MSDN tells me I do not need this operator, and the compiler acts as if it was possible implicitly (method B). What am I supposed to do?

I am aware that I can use:

Solution A

class Body : Entity
{
    Body(IntPtr pointer) : base(pointer) { }

    static Body FromEntity(Entity e)
    {
        return new Body(e.Pointer);
    }
}

Solution B

class Body : Entity
{
    Body(IntPtr pointer) : base(pointer) { }

    Body(Entity e) : base(e.Pointer) { }
}

Solution C

class Entity
{
    IntPtr Pointer;

    Entity(IntPtr pointer)
    {
        this.Pointer = pointer;
    }

    Body ToBody()
    {
        return new Body(this.Pointer);
    }
}

But honestly, all the syntaxes for these are horrible and should in fact be casts. So, any way to make the casts work? Is it a C# design flaw or did I miss a possibility? It's as if C# didn't trust me enough to write my own base-to-child conversion using their cast system.

C# Solutions


Solution 1 - C#

It's not a design flaw. Here's why:

Entity entity = new Body();
Body body = (Body) entity;

If you were allowed to write your own user-defined conversion here, there would be two valid conversions: an attempt to just do a normal cast (which is a reference conversion, preserving identity) and your user-defined conversion.

Which should be used? Would you really want is so that these would do different things?

// Reference conversion: preserves identity
Object entity = new Body();
Body body = (Body) entity;

// User-defined conversion: creates new instance
Entity entity = new Body();
Body body = (Body) entity;

Yuk! That way madness lies, IMO. Don't forget that the compiler decides this at compile-time, based only on the compile-time types of the expressions involved.

Personally I'd go with solution C - and possibly even make it a virtual method. That way Body could override it to just return this, if you want it to be identity preserving where possible but creating a new object where necessary.

Solution 2 - C#

Well, when you are casting Entity to Body, you are not really casting one to another, but rather casting the IntPtr to a new entity.

Why not create an explicit conversion operator from IntPtr?

public class Entity {
	public IntPtr Pointer;

	public Entity(IntPtr pointer) {
		this.Pointer = pointer;
	}
}

public class Body : Entity {
	Body(IntPtr pointer) : base(pointer) { }

	public static explicit operator Body(IntPtr ptr) {
		return new Body(ptr);
	}

	public static void Test() {
		Entity e = new Entity(new IntPtr());
		Body body = (Body)e.Pointer;
	}
}

Solution 3 - C#

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.

Solution 4 - C#

The reason you can't do it is because it's not safe in the general case. Consider the possibilities. If you want to be able to do this because the base and derived class are interchangeable, then you really only have one class and you should merge the two. If you want to have your cast operator for the convenience of being able to downcast base to derived, then you have to consider that not every variable typed as the base class will point to an instance of the specific derived class you are trying to cast it to. It might be that way, but you would have to check first, or risk an invalid cast exception. That's why downcasting is generally frowned upon and this is nothing more than downcasting in drag. I suggest you rethink your design.

Solution 5 - C#

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.

Solution 6 - C#

(Invoking necromancy protocols...)

Here's my use-case:

class ParseResult
{
    public static ParseResult Error(string message);
    public static ParseResult<T> Parsed<T>(T value);

    public bool IsError { get; }
    public string ErrorMessage { get; }
    public IEnumerable<string> WarningMessages { get; }

    public void AddWarning(string message);
}

class ParseResult<T> : ParseResult
{
    public static implicit operator ParseResult<T>(ParseResult result); // Fails
    public T Value { get; }
}

...

ParseResult<SomeBigLongTypeName> ParseSomeBigLongTypeName()
{
    if (SomethingIsBad)
        return ParseResult.Error("something is bad");
    return ParseResult.Parsed(new SomeBigLongTypeName());
}

Here Parsed() can infer T from it's parameter, but Error can't, but it can return a typeless ParseResult that is convertible to ParseResult<T> - or it would be if not for this error. The fix is to return and convert from a subtype:

class ParseResult
{
    public static ErrorParseResult Error(string message);
    ...
}

class ErrorParseResult : ParseResult {}

class ParseResult<T>
{
    public static implicit operator ParseResult<T>(ErrorParseResult result);
    ...
}

And everything is happy!

Solution 7 - C#

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.

Solution 8 - C#

you can use generic, its possible like blow

public class a<based>
    {
        public static implicit operator b(a<based> v)
        {
            return new b();
        }
    }

    public class b
        : a<b>
    {
    }

Solution 9 - C#

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.

Solution 10 - C#

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.

Solution 11 - C#

Ugg, I ended up just doing a simple Cast() method inside my modified entity. Maybe I am just missing the point, but I need to modify my base type so I can keep my code inside the new object to do x. I would have used public static explicit operator if the compiler would let me. The inheritance messes it up explicit cast operator.

Usage:

var newItem = UpgradedEnity(dbItem);
var stuff = newItem.Get();

Sample:

public class UpgradedEnity : OriginalEnity_Type
    {
        public string Get()
        {
            foreach (var item in this.RecArray)
            {
                //do something
            }
            return "return something";
        }

        public static UpgradedEnity Cast(OriginalEnity_Type v)
        {
            var rv = new UpgradedEnity();
            PropertyCopier<OriginalEnity_Type, UpgradedEnity>.Copy(v, rv);
            return rv;
        }

        public class PropertyCopier<TParent, TChild> where TParent : class
                                            where TChild : class
        {
            public static void Copy(TParent from, TChild to)
            {
                var parentProperties = from.GetType().GetProperties();
                var childProperties = to.GetType().GetProperties();

                foreach (var parentProperty in parentProperties)
                {
                    foreach (var childProperty in childProperties)
                    {
                        if (parentProperty.Name == childProperty.Name && parentProperty.PropertyType == childProperty.PropertyType)
                        {
                            childProperty.SetValue(to, parentProperty.GetValue(from));
                            break;
                        }
                    }
                }
            }
        }
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLazloView Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#Igor ZevakaView Answer on Stackoverflow
Solution 3 - C#robyawView Answer on Stackoverflow
Solution 4 - C#sirideView Answer on Stackoverflow
Solution 5 - C#Jaroslav JandekView Answer on Stackoverflow
Solution 6 - C#Simon BuchanView Answer on Stackoverflow
Solution 7 - C#Ken KinView Answer on Stackoverflow
Solution 8 - C#Milad SadeghiView Answer on Stackoverflow
Solution 9 - C#david marcusView Answer on Stackoverflow
Solution 10 - C#Alex KonnenView Answer on Stackoverflow
Solution 11 - C#OmzigView Answer on Stackoverflow