Как указано в других ответах, вы не можете сделать это, потому что вы пытаетесь применить выполнения литья в время компиляции конверсионных операций.
Если вы хотите избежать dynamic
, потому что вы не хотите использовать DLR .NET 4.0, вы можете использовать отражение, чтобы найти операторов преобразования самостоятельно. Не могу прокомментировать производительности для однако ваше конкретное приложение делает это:
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");
}
или для .NET 3.5 с 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");
}
Использование:
float2D V = new float2D(1, 1);
Point P = Point.Empty;
P = Convert<Point>(V); //passes
P = Convert<Point>((V as object)); //passes
Вы можете добавить «op_Implicit «а также если вы хотите конвертировать через неявные операторы.
Другой вариант, если вы хотите, чтобы избежать отражения, чтобы заранее зарегистрировать функции преобразования, некоторые отливки и Lookups типа, чтобы определить, какой оператор преобразования использовать.
Просто предостережение. В решении есть несколько проблем (безопасность потоков, предположение о том, что существуют функции преобразования, регистрация встречных/дублирующих функций преобразования вызывает ошибки), поэтому используйте на свой страх и риск или используйте его в качестве руководства для изменения, поскольку оно соответствует вашим потребностям.
Основная суть заключается в определении простого конвертера, чтобы обернуть функции преобразования себя:
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);
}
}
Затем утилита, вы можете зарегистрировать эти преобразования с помощью:
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);
}
}
Для использования, сначала вы должны зарегистрируйте функции преобразования, которые вы ожидаете использовать в своем приложении (в идеале выполните регистрацию при запуске приложения, чтобы избежать проблем с потоком):
ConversionUtility.RegisterConversion((float2D obj) => (Point)obj);
Тогда ваше использование преобразования:
float2D V = new float2D(1, 1);
Point P = Point.Empty;
P = ConversionUtility.Convert<Point>(V); //passes
P = ConversionUtility.Convert<Point>((V as object)); //passes
Не уверен, что производительность одного над другим для вашего конкретного использования приложения. Первый пример немного более гибкий, так как он выполняет проверку во время выполнения, и вам не нужно предварительно регистрировать конверсии, которые вы ожидаете использовать. Второй может быть немного более стабильным, поскольку вы регистрируете только конверсии, которые вы ожидаете использовать, и нет никакого отражения, просто кастинг и поиск в словарях.
См. [Представление и идентификация] (http://blogs.msdn.com/b/ericlippert/archive/2009/03/19/representation-and-identity.aspx) – Johnbot
Кроме этого; почему вы бросаете X и Y в целые числа? –
@daveL - я бы предположил его, потому что [конструктор для точки] (http://msdn.microsoft.com/en-us/library/s9b80s6c%28v=vs.110%29.aspx) принимает целые числа. – Jamiec