方法可以拒绝Vector2&的错误类型。的Vector3

时间:2017-05-17 01:53:35

标签: c# unity3d

如果我有方法:

public void SetPosition(Vector3 position){
   // do stuff
}

我传递了一个Vector2,为什么它仍然允许它并自动将其转换为(x,y,0)?

有没有办法让方法更严格和错误,而不是自动转换向量?我偶尔会在没有意识到的情况下犯这个错误,并且会让我花一些时间来解决这个错误。

为什么C#甚至允许程序员在传递争论时能够做到这一点?

4 个答案:

答案 0 :(得分:3)

我不知道哪个库定义了Vector2和Vector3类,但我希望有一个隐式的conversion operator。此行为已由定义这些类的库实现。

一种可能的解决方案是定义第二个接受Vector2并抛出的Position方法:

public void Position(Vector2 position){
  throw new InvalidOperationException();
}

答案 1 :(得分:2)

您无法解决此问题,因为您使用的库提供转换。

Unity为Vector2记录的here

定义了一个隐式转换运算符
  

Vector2转换为Vector3

     

Vector2可以隐式转换为Vector3z在结果中设置为零。

这与您的观察结果一致:对方法Position的调用分两步完成 - 首先,Vector2转换为Vector3z设置为零,然后将结果传递给Position

有一个技巧可以用来击败转换运算符,但它会降低你的代码的可读性,所以我建议不要这样做。这个想法是基于这样一个事实:C#不会应用两个隐式转换运算符来满足方法调用,所以你可以这样做:

class Vector3Wrap {
    private readonly Vector3 v;
    private Vector3Wrap(Vector3 v) {
        this.v = v;
    }
    public static implicit operator Vector3Wrap(Vector3 v) {
        return new Vector3Wrap(v);
    }
    public static implicit operator Vector3(Vector3Wrap w) {
        return w.v;
    }
}

public void SetPosition(Vector3Wrap positionWrap){
    Vector3 position = positionWrap;
   // do stuff
}

现在,对SetPosition(myVector3)的调用会成功,因为Vector3Wrap会隐式创建,但调用SetPosition(myVector2)会失败,因为没有从Vector2隐式转换为{ {1}}。

答案 2 :(得分:2)

  

为什么它仍然允许它并自动将其转换为(x,y,0)?

原因是Vector2结构的作者写了一个隐式转换为Vector3。由于这是Unity3d引擎的一部分,因此您无法真正改变它。

  

有没有办法让方法更严格和错误,而不是自动转换向量?

没有编译器选项可以关闭隐式转换。

  

为什么C#甚至允许程序员在传递争论时能够做到这一点?

它允许该类型的作者定义" natural"用户不想要考虑。现在"自然"是一个透视问题。我同意,当你认为它们不自然变得非常痛苦时,图书馆作者必须要小心它们。有guidelines for implicit conversions。由于Unity3d似乎定义了从Vector3到Vector2的隐式转换,丢弃了z组件,因此它们不符合它们,这是一个不幸的设计决策。然而,这甚至不是您遇到问题的转换。无论哪种方式,你都会坚持使用这个库。

如果我真的想强制执行一个不应该随便转换为Vector3,我可能会写一些包装类型并使用它。一个非常基本的实现是

struct MyVector2
{
    private Vector2 _value;

    public MyVector2(Vector2 v) 
    {
        _value = v;
    }

    public Vector2 Value { get { return _value; } }

    public Vector3 ToVector3()
    {
        return Value;
    }

    public static implicit operator Vector2(MyVector2 v)
    {
        return v.Value;
    }
}

所以这个包装器会在Vector2周围。它允许隐式转换为Vector2,以便与任何内置方法接受使用,但要传递给Vector3,您可以使用ToVector3方法。请注意,Value仍可隐式转换,因此请小心。这样,您就不必在示例中修改SetPosition。

答案 3 :(得分:0)

正如其他人所说,隐式转换无法阻止,因为它内置于 UnityEngine 中。但是,您仍然可以通过添加接受不需要的类型并引发异常的方法的重载来防止此行为产生错误:

public void SetPosition(Vector3 position) {
   // do stuff
}

public void SetPosition(Vector2 position) {
    throw new System.Exception("Implicit conversion not allowed");
}

如果您不小心传入了 Vector2,系统会自动使用重载,因为它是更好的匹配项,并且您会收到有关执行可能导致意外结果的操作的通知。