As stated by other answers, you can't do this because you're trying to apply runtime casting to compile time conversion operations.
If you want to avoid dynamic
because you don't want to use .NET 4.0's DLR, you could use reflection to find the conversion operators yourself. Can't comment on performance for your particular application doing this however:
public static TOutgoing Convert<TOutgoing>(object obj)
{
Type incomingType = obj.GetType();
MethodInfo conversionOperator = null;
foreach(var method in incomingType.GetMethods(BindingFlags.Static | BindingFlags.Public))
{
if (
method.Name == "op_Explicit" && //explicit converter
method.ReturnType == typeof(TOutgoing) && //returns your outgoing ("Point") type
method.GetParameters().Length == 1 && //only has 1 input parameter
method.GetParameters()[0].ParameterType == incomingType //parameter type matches your incoming ("float2D") type
)
{
conversionOperator = method;
break;
}
}
if (conversionOperator != null)
return (TOutgoing)conversionOperator.Invoke(null, new object[]{obj});
throw new Exception("No conversion operator found");
}
Or for .NET 3.5 with LINQ:
public static TOutgoing Convert<TOutgoing>(object obj)
{
Type incomingType = obj.GetType();
var conversionOperator = incomingType.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "op_Explicit")
.Where(m => m.ReturnType == typeof(TOutgoing))
.Where(m => m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == incomingType)
.FirstOrDefault();
if (conversionOperator != null)
return (TOutgoing)conversionOperator.Invoke(null, new object[]{obj});
throw new Exception("No conversion operator found");
}
Usage:
float2D V = new float2D(1, 1);
Point P = Point.Empty;
P = Convert<Point>(V); //passes
P = Convert<Point>((V as object)); //passes
You can add "op_Implicit" as well if you wish to convert via implicit operators.
Another option if you want to avoid reflection is to pre-register the conversion functions, some casting and type lookups to determine which conversion operator to use.
Just a caveat, the solution here has a couple issues (thread safety, assumption that conversion functions exist, registering colliding/duplicate conversion functions throws errors) so use at your own risk or use it as a guide to modify as it suits your needs.
Basic gist is to define a simple converter to wrap the conversion functions themselves:
public interface IConverter
{
object Convert(object incomingObject);
}
public class Converter<TIncoming, TOutgoing> : IConverter
{
private Func<TIncoming, TOutgoing> ConversionFunction;
public Converter(Func<TIncoming, TOutgoing> conversionFunction)
{
this.ConversionFunction = conversionFunction;
}
public object Convert(object incomingObject)
{
TIncoming typedIncomingObject = (TIncoming)incomingObject;
return ConversionFunction(typedIncomingObject);
}
}
Then a utility that you can register these conversions with:
public static class ConversionUtility
{
private static Dictionary<Type, Dictionary<Type, IConverter>> Converters = new Dictionary<Type, Dictionary<Type, IConverter>>();
public static void RegisterConversion<TIncoming, TOutgoing>(Func<TIncoming, TOutgoing> conversionFunction)
{
if (!Converters.ContainsKey(typeof(TIncoming)))
{
Converters[typeof(TIncoming)] = new Dictionary<Type, IConverter>();
}
Converters[typeof(TIncoming)].Add(typeof(TOutgoing), new Converter<TIncoming, TOutgoing>(conversionFunction));
}
public static TOutgoing Convert<TOutgoing>(object obj)
{
Type incomingType = obj.GetType();
IConverter converter = Converters[incomingType][typeof(TOutgoing)];
return (TOutgoing)converter.Convert(obj);
}
}
For usage, first you must register the conversion functions you expect to use in your application (ideally perform the registration when your application starts up to avoid threading issues):
ConversionUtility.RegisterConversion((float2D obj) => (Point)obj);
Then your conversion usage:
float2D V = new float2D(1, 1);
Point P = Point.Empty;
P = ConversionUtility.Convert<Point>(V); //passes
P = ConversionUtility.Convert<Point>((V as object)); //passes
Not sure about the performance of one over the other for your particular application usage. The first sample is a bit more flexible as it performs the check at runtime and you don't have to pre-register the conversions you expect to use. The second might be a bit more stable as you only register the conversions you expect to use and there is no reflection, just casting and dictionary lookups.
explicit
andimplicit
conversion operators are evaluated at compile time. That means that the types as you have them at compile time must be fully known to apply those operators. When you convertV
toobject
, you've essentially lost the type information and the compiler cannot make the determination to use the conversion operator you defined onfloat2D
. However you can cheat using thedynamic
keyword; this will cause the Dynamic Language Runtime to evaluate at runtime if there is a conversion operator or not. Try casting toobject
, then todynamic
, then toPoint
. – Fenestradynamic
for that purpose unless you really need to; most likely you can solve it in other ways. Perhaps with a utility function that checks the type of the incoming object, casts it to its compile-time type (float2D
) if it's compatible, then casts/converts it to aPoint
object. – Fenestraobject
variables. – Crud