在C#中的基类中使用泛型:如何确保基类中的方法返回派生类的类型?

问题描述 投票:0回答:1

我正在使用一个类库,用于各种度量单位。我试图避免尽可能多地重复代码,这应该非常简单,因为从数学上来说,将两个长度加在一起还是将两个速度加在一起并不重要-您只需将它们转换为相同的单位,然后加。我thought使用基类和泛型可以很容易地做到这一点...

// A measurement consists of a Value (double) and
// a Unit (an Enum for the various unit types).

public class Measurement<TUnit>
    where TUnit : struct
{
    protected Measurement(double value, TUnit unit)
    {
        _value = value;
        _unit = unit;
    }

    protected double _value;
    protected TUnit _unit;

    public double Value => _value;
    public TUnit Unit => _unit;

    ...
    // Conversion Methods - these will get overridden in the derived classes.
    protected virtual double GetValueAs(TUnit unit) => throw new NotImplementedException();
    ...

    // Operator overloads
    public static Measurement<TUnit> operator +(Measurement<TUnit> left,
                                                Measurement<TUnit> right)
    {
        return new Measurement<TUnit>(left.Value + right.GetValueAs(left.Unit), left.Unit);
    }
}

并且此类为每个单元派生,如下所示:

public sealed class Length : Measurement<LengthUnit>
{
    // Using a private constructor and public static factory methods
    private Length(double value, LengthUnit unit)
        : base(value, unit) { }

    ...
}

我的问题是,每当我尝试使用任何返回Measurement<TUnit>的基类类型时,这些方法显然都会返回Measurement<TUnit>对象。

Length length1 = Length.FromMeters(1); // length1 is 1 meter

Length length2 = Length.FromMeters(2); // length2 is 2 meters

Length length3 = length1 + length2;    // Error CS0266: Cannot implicitly convert type
                                       // 'Measurement<LengthUnit>' to 'Length'.
                                       // An explicit conversion exists (are you missing a cast?)

var varlength3 = length1 + length2;    // This works, but varlength3 is type Measurement<LengthUnit>
                                       // so I can't use any methods in the Length class.

我想念的是什么?甚至有可能做我想做的事情?我需要咬一口子,然后将相同的代码复制到每个单元类中吗?

c# generics inheritance base-class
1个回答
0
投票

检查操作员过载:

// Operator overloads
public static Measurement<TUnit> operator +(Measurement<TUnit> left,
                                            Measurement<TUnit> right)
{
    return new Measurement<TUnit>(left.Value + right.GetValueAs(left.Unit), left.Unit);
}

您正在返回Measurement<TUnit>对象。因此,无法确定Measurement<TUnit>类是否始终是长度对象的编译器,需要进行类似于

的转换
Length length3 = (LengthUnit)(length1 + length2;

您可以通过创建用于添加Length的新运算符来添加Length对象来避免这种情况。

© www.soinside.com 2019 - 2024. All rights reserved.