【问题标题】:Why is this generic class generating a compiler error?为什么这个泛型类会产生编译器错误?
【发布时间】:2019-12-09 18:35:15
【问题描述】:

我有这门课:

public class Transform<PositionType, RotationType, ScaleType>
    where PositionType : Position
    where RotationType : Rotation
    where ScaleType : Scale
{
    public Transform<PositionType, RotationType, ScaleType> Parent;

    public PositionType GlobalPosition;
    // The next line has a compile error: Cannot implicitly convert type 'Position' 
    // to 'PositionType'.  An explicit conversion exists (are you missing a cast?)
    public PositionType LocalPosition => Parent.GlobalPosition - GlobalPosition;

    public RotationType GlobalRotation;
    // The next line has a compile error: Cannot implicitly convert type 'Rotation' 
    // to 'RotationType'. An explicit conversion exists (are you missing a cast?)
    public RotationType LocalRotation => Parent.GlobalRotation - GlobalRotation; 

    public ScaleType GlobalScale;
    // The next line has a compile error: Cannot implicitly convert type 'Scale' 
    // to 'ScaleType'. An explicit conversion exists (are you missing a cast?)
    public ScaleType LocalScale => Parent.GlobalScale - GlobalScale; 
}

Position:(Scale和Rotation定义相同)

public class Position
{
    public Position(int axis)
    {
        Axis = new float[axis];
    }

    public Position(float[] axis)
    {
        Axis = axis;
    }

    public static Position operator -(Position a, Position b)
    {
        if (a.Axis.Length != b.Axis.Length)
        {
            throw new System.Exception("The axis of the two Positions are not comparable.");
        }

        Position difference = new Position(a.Axis);

        for (int i = 0; i < difference.Axis.Length; i++)
        {
            difference.Axis[i] = a.Axis[i] - b.Axis[i];
        }

        return difference;
    }

    public float[] Axis;
}

对我来说这看起来完全有效,所以我很困惑为什么它会产生编译时错误。 在保留此功能的同时,我应该如何解决此问题?

【问题讨论】:

  • 错误信息非常具体,告诉你该怎么做。哪部分不明白?
  • 顺便说一句,这些类型参数名称更习惯用法为TPositionTRotationTScale
  • 我的猜测是您的线性代数运算符(例如Parent.Rotation - Rotation)不受限制生成与传入类型相同的通用子类型。 IE。 Parent.Rotation - Rotation 不能保证是 RotationType 类型,即使 Parent.RotationRotation 是;它只是保证是Rotation 类型。需要查看minimal reproducible example 才能确定。
  • ScalePositionRotation的定义是什么?
  • 是的,所以 Position operator -(Position a, Position b) 只能保证生成 Position 而不是它的子类 PositionType,即使 ab 是子类型 PositionType。而且实际上没有办法在c#中直接创建这样一个通用运算符+,参见C# Generic Operators

标签: c# generics


【解决方案1】:

您可以使用接口执行此操作,但您必须在每个派生类中实现减法逻辑。

public interface ISubtractable<T>
{
    T Subtract(T subtrahend);
}

public abstract class Position
{
    public float[] Axis;

    public Position(int axis)
    {
        Axis = new float[axis];
    }

    public Position(float[] axis)
    {
        Axis = axis;
    }
}

public class DerivedPosition : Position, ISubtractable<DerivedPosition>
{
    public DerivedPosition(int axis)
        : base(axis)
    { }

    public DerivedPosition(float[] axis)
        : base(axis)
    { }

    public DerivedPosition Subtract(DerivedPosition subtrahend)
    {
        if(Axis == subtrahend.Axis)
        {
            throw new System.Exception("The axis of the two Positions are not comparable.");
        }

        DerivedPosition difference = new DerivedPosition(Axis);

        for (int i = 0; i < difference.Axis.Length; i++)
        {
            difference.Axis[i] = Axis[i] - subtrahend.Axis[i];
        }

        return difference;
    }
}

public class Transform<TPosition, TRotation, TScale>
    where TPosition : ISubtractable<TPosition>
    where TRotation : ISubtractable<TRotation>
    where TScale : ISubtractable<TScale>
{
    public Transform<TPosition, TRotation, TScale> Parent;

    public TPosition GlobalPosition;

    public TPosition LocalPosition => Parent.GlobalPosition.Subtract(GlobalPosition);

    // etc.
}

【讨论】:

    【解决方案2】:

    我可能是错的,但是如果您将局部变量名称更改为与类型不同会发生什么 --- 例如

     public PositionType myPosition;
     public PositionType LocalPosition => Parent.myPosition - myPosition;
    

    【讨论】:

    • 更改命名并没有解决问题,但确实使代码更具可读性。我会更新问题。
    【解决方案3】:

    您的用例是什么样的,我不清楚您是否需要将其设为通用? PositionRotationScale 是基类吗?

    public class Transform
    {
        public Transform Parent;
    
        public Position GlobalPosition;
    
        public Position LocalPosition => Parent.GlobalPosition - GlobalPosition;
    
        public Rotation GlobalRotation;
    
        public Rotation LocalRotation => Parent.GlobalRotation - GlobalRotation; 
    
        public Scale GlobalScale;
    
        public Scale LocalScale => Parent.GlobalScale - GlobalScale; 
    }
    

    【讨论】:

    • 是的,它们是基类。我的意图是,然后可以有像“Point3D”这样的类,其中“轴”的大小为 3,X Y 和 Z 的属性只引用 Axis[0] 和 [1] Aso。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    相关资源
    最近更新 更多