如何检查通用枚举是否有价值?

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

在我的 C# 应用程序中,我有一个抽象类,它是 UnitsNet 库的包装器,用于对密切相关的属性(例如用户选择的数值和该值的单位)进行分组,以限制可用的测量单位,并且还处理来自用户的复杂输入(例如多个数字输入,例如“5,8,10:1:20”)。这是基类和扩展它的类之一:

public abstract class PropertyBase<TQuantity, TUnit> : where TQuantity : IQuantity where TUnit : Enum
{
    public string InputString { get; set; }

    public TUnit? SelectedUnit
    {
        get => _selectedUnit;
        set
        {
            var oldUnit = _selectedUnit;
            _selectedUnit = value;
            if (oldUnit != null) //This check doesn't work
            {
                //This code should only be run if oldUnit is not null or 0
                ConvertInputString(oldUnit, value);
            }
        }
    }
    
    private TUnit? _selectedUnit;
    protected abstract TUnit[] AvailableUnits { get; }
    protected abstract TQuantity FromValue(double value, TUnit unit);
    protected abstract double As(TQuantity quantity, TUnit unit);
    
    private void ConvertInputString(TUnit oldUnit, TUnit newUnit)
    {
        //Parses and converts values in InputString
    }
    protected List<double> ParseInputValues(string input)
    {
        //...
    }
}

public class InputPropertyAngles : PropertyBase<Angle, AngleUnit>, IInputProperty 
{
    public InputPropertyAngle()
    {
        SelectedUnit = AngleUnit.Degree;
    }
    public override double[] ValuesInSi
    {
        get
        {
            var values = ParseInputValues(InputString).ToArray();
            return values.Select(value => Angle.From(value, SelectedUnit).Degrees).ToArray();
        }
    }
    
    protected override AngleUnit[] AvailableUnits => [AngleUnit.Degree, AngleUnit.Radian];
    protected override Angle FromValue(double value, AngleUnit unit) => Angle.From(value, unit);
    protected override double As(Angle quantity, AngleUnit unit) => quantity.As(unit);
}

请注意,

AngleUnit
是来自UnitsNet库的Enum。

这个想法是,当

InputPropertyAngle
被实例化,并且
SelectedUnit
在构造函数中设置为默认单位时,
ConvertInputString
不应该运行。这是通过检查
oldUnit
是否为空 (
if (oldUnit != null)
) 来完成的。但是,由于
oldUnit
TUnit
(通用枚举),因此它不能为空。在运行时,它假定值为 0。

幸运的是,在UnitsNet库中,在

AngleUnit
枚举中,0不代表任何有意义的值。所以我想我可以用
if (oldUnit != 0)
替换该检查,但编译器说
Cannot apply operator '!=' to operands of type 'TUnit' and 'int'
。不幸的是,我不能将
TUnit
限制为比 Enum 更具体的东西,因为
AngleUnit
LengthUnit
MassUnit
和来自 UnitsNet 的其他枚举没有任何通用接口(据我所知,枚举不能有根本就是这样)。

解决这个问题以使空检查成为可能的最优雅的方法是什么?

c# enums constraints nullable
2个回答
0
投票

您可以将

TUnit
限制为
struct
并删除可空性并使用
default
(我将其移至虚拟属性,以便继承者可以根据需要重新定义
Default
):

public abstract class PropertyBase<TQuantity, TUnit> where TQuantity : IQuantity where TUnit : struct, Enum
{
    protected virtual TUnit Default => default;

    public TUnit SelectedUnit
    {
        get => _selectedUnit;
        set
        {
            var oldUnit = _selectedUnit;
            _selectedUnit = value;
            if (!oldUnit.Equals(Default)) 
            {
                //This code should only be run if oldUnit is not null or 0
                ConvertInputString(oldUnit, value);
            }
        }
    }

或者使用可空性:

public abstract class PropertyBase<TQuantity, TUnit> where TQuantity : IQuantity where TUnit : struct, Enum
{
    public TUnit? SelectedUnit
    {
        get => _selectedUnit;
        set
        {
            var oldUnit = _selectedUnit;
            _selectedUnit = value;
            if (oldUnit is not null && value is not null) 
            {
                //This code should only be run if oldUnit is not null or 0
                ConvertInputString(oldUnit.Value, value.Value);
            }
        }
    }

0
投票

尝试将

TEnum
限制为 struct Enum。

public abstract class PropertyBase<TQuantity, TUnit> 
    where TQuantity : IQuantity
    where TUnit : struct, Enum
{
    public TUnit? SelectedUnit
    {
        get => _selectedUnit;
        set
        {
            var oldUnit = _selectedUnit;
            _selectedUnit = value;
            if (oldUnit is Enum nonNull)
            {
            }
            else
            {
                // Code will not run
            }
        }
    }
    // You couldn't do this before but now you should be ablt to.
    private TUnit? _selectedUnit = null;
    .
    .
    .
}
© www.soinside.com 2019 - 2024. All rights reserved.