I’m presently writing a framework that wraps a C API using interop. Many of the classes/structs defined in the C library already exist in .NET, but I have to re-implement them anyway so that I can interface with the library. People accustomed to the .NET classes won’t be fond of this because they already have a set of classes that work well, and the new ones won’t work with existing .NET methods. There is a simple solution to this, however! Implicit casting!
Here’s a sample of how I made my Color struct compatible with the one defined in System.Drawing.Color:
public struct Color
{
public byte R, G, B, A;
public static implicit operator System.Drawing.Color(Color c)
{
return System.Drawing.Color.FromArgb(c.A, c.R, c.G, c.B);
}
public static implicit operator Color(System.Drawing.Color c)
{
return new Color {R = c.R, G = c.G, B = c.B, A = c.A};
}
}
Note that System.Drawing.Color uses ints instead of bytes for its colors, and they aren’t necessarily stored in the same memory location, so I couldn’t use that class directly. You can, however, convert back and forth between the two classes without any loss of data, so this is a perfect case for implicit casting. If the two classes aren’t convertible without some data changing, you should use explicit casting instead, or perhaps a static factory method.
I was curious, however, to know what would happen if an implicit casting method was defined in both classes. Here’s an example:
{
public static implicit operator B(A a)
{
Console.WriteLine("A::B");
return new B();
}
}
class B
{
public static implicit operator B(A a)
{
Console.WriteLine("B::B");
return new B();
}
}
class Program
{
public static void F(B b)
{
Console.WriteLine("F()");
}
static void Main(string[] args)
{
var a = new A();
F(a);
Console.ReadLine();
}
}
How does it know which method to call? The answer: it doesn’t! This actually gives the following error:
Ambiguous user defined conversions ‘ImplicitTest.A.implicit operator ImplicitTest.B(ImplicitTest.A)’ and ‘ImplicitTest.B.implicit operator ImplicitTest.B(ImplicitTest.A)’ when converting from ‘ImplicitTest.A’ to ‘ImplicitTest.B’
There is a way you can still utilize one of conversion methods, but it isn’t pretty. Here’s the solution work-around:
{
var method = typeof (A).GetMethod("op_Implicit", new[] {typeof (A)});
var converter = (Func<A, B>) Delegate.CreateDelegate(typeof (Func<A, B>), method);
var a = new A();
F(converter.Invoke(a));
Console.ReadLine();
}
The real solution would be to just delete one of the methods, if you can!
Leave a comment