C#显式运算符和对象

C#显式运算符和对象,c#,typeconverter,explicit-conversion,C#,Typeconverter,Explicit Conversion,问题 请先看一下代码 这是我的自定义类: public class float2D { public float X { get; private set; } public float Y { get; private set; } public float2D(float x, float y) { this.X = x; this.Y = y; } public static explicit operat

问题

请先看一下代码

这是我的自定义类:

public class float2D
{
    public float X { get; private set; }
    public float Y { get; private set; }

    public float2D(float x, float y)
    {
        this.X = x;
        this.Y = y;
    }

    public static explicit operator Point(float2D x)
    {
        return new Point((int)x.X, (int)x.Y);
    }

    ...
}
下面是我编写的测试代码:

    private void TEST()
    {
        float2D V = new float2D(1, 1);
        Point P = Point.Empty;
        P = (Point)V; // Works
        P = (Point)(V as object); // Specified cast is not valid.
    }
如您所见,当值类型未知时,转换值失败。我相信这是因为它在对象类中搜索非实数类型的操作数。我怎样才能解决这个问题

我有一个代码,其中所有内容都是对象,它必须处理这些对话

如果你有什么想法,请告诉我


避免动态

好的,让我们以你能看到我到底想做什么和我的情况的方式来更改示例

以下是我的课程:

    class TEST
    {
        dynamic OBJECT;
        public void STORE<T>(ref T V)
        {
            this.OBJECT = V;
        }

        public T CONVERT<T>()
        {
            return (T)this.OBJECT;
        }
    }
类测试
{
动态对象;
公共空库(参考T V)
{
这个物体=V;
}
公共T CONVERT()
{
返回(T)this.OBJECT;
}
}
下面是测试代码:

        float2D V = new float2D(1, 1);
        TEST t = new TEST();
        t.STORE(ref V);
        Point P = t.CONVERT<Point>();
float2dv=新的float2D(1,1);
测试t=新测试();
t、 仓库(参考V);
点P=t.CONVERT();

有没有办法让dynamic从课堂上消失,让它继续工作?我真的想避免.Net4/4.5

这是因为您正在将它强制转换为
对象,而您没有明确的强制转换,它不会隐式地假定您希望它成为
浮动2D

是的,这两件事截然不同。第一行:

P = (Point)V; // Works
使用显式转换运算符,该运算符对于此组合是重载的。然而,第二个问题是:

P = (Point)(V as object); // Specified cast is not valid.
这将引用
V
强制转换为
对象
(我们通常都知道它是),然后分别从
对象
强制转换为

由于
是一个
结构
,因此它会尝试“取消装箱”相同的引用,就像它是一个装箱的
。但是它不是一个装箱的
点,因此错误是正确的。转换运算符不是多态的,仅当框包含相应类型的装箱副本时才允许取消装箱(注意:可以将枚举作为整数取消装箱,将整数取消装箱作为枚举-只要基础类型匹配)


但是,即使
是一个
,它仍然会失败,并出现类似的错误:如果类型不兼容,则保留引用的强制转换也不起作用。

如其他答案所述,您不能这样做,因为您正试图将运行时强制转换应用于编译时转换操作

如果因为不想使用.NET 4.0的DLR而希望避免使用
动态
,则可以使用反射自己查找转换运算符。无法对执行此操作的特定应用程序的性能进行评论,但是:

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");
}
然后您的转换使用:

float2D V = new float2D(1, 1);
Point P = Point.Empty;
P = ConversionUtility.Convert<Point>(V); //passes
P = ConversionUtility.Convert<Point>((V as object)); //passes
float2dv=新的float2D(1,1);
点P=点。空;
P=转换利用率。转换(V)//通行证
P=ConversionUtility.Convert((V作为对象))//通行证

对于您的特定应用程序使用情况,不确定其中一个的性能优于另一个。第一个示例更加灵活,因为它在运行时执行检查,并且您不必预先注册您希望使用的转换。第二种可能更稳定,因为您只注册预期使用的转换,并且没有反射,只需强制转换和字典查找。

寻找一个真正的过度工程化解决方案,该解决方案结合使用反射和他的记忆转换方法,以保持性能,同时也不需要调用
conversion.RegisterConversion()

使用系统;
使用System.Collections.Generic;
使用System.Linq;
运用系统反思;
公共静态类ConvertUtil
{
/// 
///转换为类型
///使用反射确定适当的显式或隐式强制转换
///接线员。
/// 
/// 
///要转换为的类型。
/// 
///正在转换的对象。
/// 
///扮演。
/// 
/// 
///在运行时检测类型的类型。这是一个
///如果频繁使用,性能会受到轻微影响。
/// 
/// 
公共静态TResult ConvertTo(对象源),其中TResult:class
{
if(source==null | | sosurce是TResult)
{
返回源;
}
类型sourceType=source?.GetType();
return(TResult)GetConverter(sourceType,typeof(TResult))?.Invoke(source)??
抛出新的InvalidCastException($“没有来自类型的隐式或显式强制转换”+
$“{sourceType.Name}到{resultType.Name}存在。”);
}
/// 
///转换为类型
///使用反射确定适当的显式或隐式强制转换
///接线员。
/// 
/// 
///正在从转换类型。
/// 
/// 
///要转换的类型
///对。
/// 
///正在转换的对象。
/// 
///扮演。
/// 
/// 
///在编译时检测
///与使用时相比,性能略有提高
///经常。
/// 
/// 
公共静态TResult ConvertTo(TSource源)
where TSource:class
结果:在哪里上课
{
if(source==null | | sosurce是TResult)
{
返回源;
}
Func转换器=
GetConverter(typeof(TSource),typeof(TResult))??
抛出新的InvalidCastException($“没有来自的隐式或显式强制转换”+
$“存在类型{sourceType.Name}到{resultType.Name}”之间的连接。”);
返回(TResult)转换器(源);
}
/// 
///锁定线程安全。如果这不是一个问题,你可以删除这个和所有
///锁的部分
/// 
私有静态只读对象s_typeConvertersLock=新对象();
/// 
///从源类型到目标类型的映射及其转换
///功能。
/// 
普里夫
float2D V = new float2D(1, 1);
Point P = Point.Empty;
P = Convert<Point>(V); //passes
P = Convert<Point>((V as object)); //passes
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