【问题标题】:Can I add an implicit conversion for two classes which I don't directly control?我可以为我不直接控制的两个类添加隐式转换吗?
【发布时间】:2011-07-28 10:47:53
【问题描述】:

我希望能够在两个不兼容的类之间进行隐式转换。

其中一个类是Microsoft.Xna.Framework.Vector3,另一个只是F# 项目中使用的Vector 类。我正在用 XNA 用 C# 编写一个 3d 游戏,而且——虽然它是用 3D 绘制的,但游戏只发生在两个维度上(它是鸟瞰图)。 F# 类使用 2D 向量处理物理:

type Vector<'t when 't :> SuperUnit<'t>> =
    | Cartesian of 't * 't
    | Polar of 't * float
    member this.magnitude =
        match this with
        | Cartesian(x, y) -> x.newValue(sqrt (x.units ** 2.0 + y.units ** 2.0))
        | Polar(m, _) -> m.newValue(m.units)
    member this.direction =
        match this with
        | Cartesian(x, y) -> tan(y.units / x.units)
        | Polar(_, d) -> d
    member this.x =
        match this with
        | Cartesian(x, _) -> x
        | Polar(m, d) -> m.newValue(m.units * cos(d))
    member this.y =
        match this with
        | Cartesian(_, y) -> y
        | Polar(m, d) -> m.newValue(m.units * sin(d))

这个向量类利用物理项目使用的单位系统,它采用原生 F# 测量单位并将它们组合在一起(距离、时间、质量等单位)。

但是 XNA 使用自己的 Vector3 类。我想添加一个从 F# Vector 到 XNA Vector3 的隐式转换,它负责哪个游戏发生的两个维度,哪个轴是“向上”等等。它d 很简单,只需 Vector v -&gt; new Vector3(v.x, v.y, 0) 或其他东西。

我不知道该怎么做。我无法在 F# 中添加隐式转换,因为类型系统(正确)不允许它。我无法将它添加到 Vector3 类,因为它是 XNA 库的一部分。据我所知,我不能使用扩展方法:

class CsToFs
{
    public static implicit operator Vector3(this Vector<Distance> v)
    {
        //...
    }
}

this 关键字有错误,并且

class CsToFs
{
    public static implicit operator Vector3(Vector<Distance> v)
    {
        return new Vector3((float)v.x.units, (float)v.y.units, 0);
    }

    public static void test()
    {
        var v = Vector<Distance>.NewCartesian(Distance.Meters(0), Distance.Meters(0));
        Vector3 a;
        a = v;
    }
}

a = v; 上的错误(无法隐式转换...)。

有没有办法做到这一点而不能将演员表放入任何一个类中?作为最后的手段,我可​​以open Microsoft.Xna.Framework 并在 F# 中进行转换,但这对我来说似乎是错误的——物理库不应该知道或关心我正在使用什么框架来编写游戏。

【问题讨论】:

    标签: c# f# operator-overloading extension-methods implicit-conversion


    【解决方案1】:

    在 C# 中你不能。您可以提供具有额外转换的后代类型(前提是这些类型不是密封的);或者您可以提供一个通用的包装类,以某种方式添加转换。

    所有这一切的便利性取决于这些包装器/适配可与原始 API 一起使用的方式。

    另外说明我看到您也在使用 F#。 IIRC F# 应该具有一定程度的元编程能力(就像 .NET 的许多函数式语言,例如 Boo 和 Nemerle)。如果可以在这里使用它,我不会感到惊讶。不幸的是,我的 F 不够敏锐,无法提供帮助

    【讨论】:

    • 我一直在考虑使用子类,但我担心它会变得过于复杂
    • 看到这两个对象都是值类型 - 我认为子类是不可能的。
    • 我尝试使用代理类进行隐式转换,但 C# 不会自动应用双重转换。 (为什么构造函数不被视为转换运算符?)
    【解决方案2】:

    不,你不能。隐式运算符必须定义为其中一个类的成员。但是,您可以定义扩展方法(您的示例不起作用,因为扩展方法必须在 public static class 中)。

    public static class ConverterExtensions
    {
        public static Vector ToVector (this Vector3 input)
        {
          //convert
        }
    }
    

    【讨论】:

    • 不敢相信我没有想到这一点,尽管这几乎正是我正在尝试的。
    • 如果您有一个用户定义的类型可以隐式转换为/从其他两种类型转换,它会起作用吗? C 型隐式从 A 型转换并隐式转换为 B 型。这样行吗?
    • 今天看到这条评论,决定试一试。不,它不起作用。我认为该语言最多只能进行 1 次转换。如果您显式转换为中间类型,那么它会起作用,但此时您最好只编写扩展方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-08
    相关资源
    最近更新 更多