【问题标题】:C# Inheritance Type Casting errorC# 继承类型转换错误
【发布时间】:2017-02-05 15:20:07
【问题描述】:

我对 C# 中的继承有点陌生。我有两个类Velocity.csPosition.cs 继承自基类Vector.cs。我正在尝试在Vector.cs 中创建一个名为subtract() 的方法,该方法可以从Velocity.csPosition.cs 访问。

这是减法的代码。

     public Vector subtract(Vector v) {
        double nx = this.x - v.x;
        double ny = this.y - v.y;
        double mag = Math.Sqrt(x * x + y * y);
        double ang = Math.Atan2(y, x);
        return new Vector(mag, ang);
    }

定义Velocity.cs类的代码如下。

class Velocity : Vector{

    public Velocity(Position p1, Position p2, double vpref) : base(p1, p2) {
        normalize();
        scale(vpref);
    }

    public Velocity(double vmax) : base(new Random().NextDouble()*vmax, new Random().NextDouble()*2*Math.PI) {

    }

    public void change(Velocity v) {
        x = v.x;
        y = v.y;
        magnitude = Math.Sqrt(x * x + y * y);
        angle = Math.Atan2(y, x);
    }

}

}

当我尝试在外部调用减法函数时,如下所示:

        Velocity v1 = new Velocity(5);
        Velocity v2 = new Velocity(7);
        Velocity result = v1.subtract(v2);

我收到一条错误消息,提示 无法在“Velocity”和“Vector”之间显式转换你忘记了演员表吗?

所以我尝试了Velocity result = (Velocity)v1.subtract(v2);,但这会导致以下错误:发生了“System.InvalidCastException”类型的未处理异常

我怎样才能重写这个函数来使它工作?我真的必须制作返回类型为VectorVelocityPosition 的函数的三个版本吗?如果是这样,继承的意义何在?我可以把它们放在相关的类中。

注意:我知道速度等级有点小,当时可能看起来毫无意义,我稍后会添加更多内容,我正在做一个项目。

【问题讨论】:

  • 旁注,不要这样做new Random()..., new Random()... 。相反,创建 Random 类的静态实例并使用它。否则你会经常得到相同的数字。
  • 另外,您的减法方法返回一个Vector。您正在尝试将其分配给Velocity 类型的变量。虽然Velocity 确实是Vector,但Vector 不一定是Velocity(它可以是Position)。您始终可以使用Vector result = v1.subtract(v2);,但您只能访问Vector 中定义的公共字段,这取决于您的用例,这可能不够,也可能不够。另一个注意事项:根据 C# 命名约定,方法名称应以大写字母开头,即Change(...)Subtract(...)
  • 我看到你喜欢第一个回答者的方法。顺便说一句,请仔细检查我的……我相信它以更直接的方式符合您的要求。

标签: c# oop inheritance casting


【解决方案1】:

我认为Vector类应该接受一个泛型类型参数,让它知道其派生类的类型:

public class Vector<TImpl> where TImpl : Vector
{
     public TImpl Subtract(TImpl v) 
     {
        double nx = this.x - v.x;
        double ny = this.y - v.y;
        double mag = Math.Sqrt(x * x + y * y);
        double ang = Math.Atan2(y, x);

        return (TImpl)Activator.CreateInstance(typeof(TImpl), new object[] { mag, ang });
    }
}

public class Velocity : Vector<Velocity>
{
}

顺便说一句,我觉得Subtract 方法应该是一个扩展方法,一切都会看起来不那么奇怪:

public static class VectorExtensions
{
      public static TImpl Subtract<TImpl>(this TImpl vectorImpl, TImpl other)
             where TImpl : Vector
      {
        double nx = this.x - v.x;
        double ny = this.y - v.y;
        double mag = Math.Sqrt(x * x + y * y);
        double ang = Math.Atan2(y, x);

        return (TImpl)Activator.CreateInstance(typeof(TImpl), new object[] { mag, ang });
      }
}

...您将能够实现您的目标:

Velocity result = v1.Subtract(v2);

【讨论】:

  • 使用 (TImpl)Activator.CreateInstance(typeof(TImpl), new object[] { mag, ang }) 在我看来很难看。
  • @JeppeStigNielsen 给我一个替代方案,我会改进 sn-p :D
  • @JeppeStigNielsen 另一种方法是使用隐式接口实现来设置一些属性而不将它们公开...
  • 不确定我是否理解。什么接口有什么属性(或方法)? 显式接口实现在某种意义上是public(如果接口类型是public;internal如果接口是那个)。
  • @JeppeStigNielsen 您知道显式实现就像实现它们的类中的 private 成员......当然,您可以将该实现转换为接口类型以获得访问其成员。
【解决方案2】:

啊,我明白这里发生了什么。因此,您的减法函数返回一个 Vector 对象,但 C# 无法将 Vector 解析回 Velocity。在复制构造函数解决它之前,我曾经遇到过这个问题。

所以在你的 Vector 类中:

public class Vector
{
    /// <summary>
    /// Copy Constructor
    /// </summary>
    /// <param name="toCopy">
    /// The vector object to copy
    /// </param>
    public Vector(Vector toCopy)
    {
        if (toCopy == null)
        {
            throw new ArgumentNullException("toCopy");
        }

        x = toCopy.x;
        y = toCopy.y;
        //What ever other properties you have, assign them here
    }
}

然后在你的 Velocity 课程中:

public class Velocity : Vector
{
    public Velocity(Vector vector)
        : base(vector)
    {
    }
}

最后,如何使用:

Velocity result = new Velocity((v1).subtract(v2));

【讨论】:

    【解决方案3】:

    请注意您的代码

    Velocity result = (Velocity)v1.subtract(v2);
    

    不会将减法的结果转换为 Velocity 类型。正确的做法是:

    Velocity result = (Velocity)(v1.subtract(v2));
    

    【讨论】:

    • 没有。那将是完全相同的事情,并不能解决他/她的问题。
    • 此评论不正确。 (T)v.s(u) 形式的东西已经被视为(T)(v.s(u)),而不是您似乎认为的((T)v).s(u)。所以额外的括号很好但不是必需的,所以你的评论是错误的。
    【解决方案4】:

    您不必编写三个版本的代码。 你可以编写一个泛型函数。

    public T Substract<T> (T vector) where T: Vector
    {
        ...
        return new T(...); // Edited to demonstrate last line as asked from comment
    }
    

    【讨论】:

    • 这是有道理的,但最后一行看起来如何? return new T(mag, ang);
    • 这是一个非常好的答案。
    • @MatíasFidemraizer 我还是做错了.. 这也不对return T where T: Vector, new(mag, ang);
    • 我不喜欢这个解决方案。为什么要对 Velocity 执行减法运算并且需要将结果类型作为泛型参数提供?看起来很奇怪。
    • @ryanmattscott new() 约束是定义T 必须提供一个公共的无参数构造函数。对其他类型的构造函数没有限制..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-10
    • 1970-01-01
    • 2014-08-07
    • 2014-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多