Units.NET添加单元无需重新编译

zer*_*dev 5 units-of-measurement nuget

我们需要在测量单位之间进行动态转换,Units.NET 似乎是理想的解决方案,但是,它缺少我们需要的一些单位(加仑每分钟)。我知道添加到规范文件并重新创建类很简单,但最好能够简单地使用 nuget 包。有谁知道一种无需重新编译 Units.NET 解决方案即可将单元添加到 Units.NET 的方法?

应该注意的是,我们并没有与 Units.NET 联姻,我们只需要能够在任意流量和长度单位之间进行转换。

谢谢!

ang*_*sen 1

在 Units.NET 的 github issues page上询问这个问题可能会得到更好的答复。有一个关于在主库之外添加自定义单元的wiki 页面,但我承认这部分不太完善,需要改进。

从维基复制:

如果您希望向 UnitsNet nuget 添加新的数量或单位,请参阅https://github.com/angularsen/UnitsNet/wiki/Adding-a-New-Unit

单位.NET结构

Units.NET大致由以下部分组成:

  • 长度和力等数量
  • 单位枚举值,例如 LengthUnit.Meter 和 ForceUnit.Newton
  • UnitAbbreviationsCache、UnitParser、QuantityParser 和 UnitConverter 用于解析和转换数量和单位
  • 用于定义单位、转换函数和缩写的 JSON 文件
  • CodeGen.exe 基于 JSON 文件生成 C# 代码

示例:自定义数量 HowMuch,单位为 HowMuchUnit

将单位枚举值映射到单位缩写

UnitAbbreviationsCache.Default.MapUnitToDefaultAbbreviation(HowMuchUnit.Some, "sm");
UnitAbbreviationsCache.Default.MapUnitToDefaultAbbreviation(HowMuchUnit.Lots, "lts");
UnitAbbreviationsCache.Default.MapUnitToDefaultAbbreviation(HowMuchUnit.Tons, "tns");
Run Code Online (Sandbox Code Playgroud)

从枚举值查找单位缩写

Console.WriteLine("GetDefaultAbbreviation(): " + string.Join(", ", 
    UnitAbbreviationsCache.Default.GetDefaultAbbreviation(HowMuchUnit.Some), // "sm"
    UnitAbbreviationsCache.Default.GetDefaultAbbreviation(HowMuchUnit.Lots), // "lts"
    UnitAbbreviationsCache.Default.GetDefaultAbbreviation(HowMuchUnit.Tons)  // "tns"
));
Run Code Online (Sandbox Code Playgroud)

Parse unit abbreviations back to enum values

Console.WriteLine("Parse<HowMuchUnit>(): " + string.Join(", ",
    UnitParser.Default.Parse<HowMuchUnit>("sm"),  // Some
    UnitParser.Default.Parse<HowMuchUnit>("lts"), // Lots
    UnitParser.Default.Parse<HowMuchUnit>("tns")  // Tons
));
Run Code Online (Sandbox Code Playgroud)

Convert between units of custom quantity

var unitConverter = UnitConverter.Default;
unitConverter.SetConversionFunction<HowMuch>(HowMuchUnit.Lots, HowMuchUnit.Some, x => new HowMuch(x.Value * 2, HowMuchUnit.Some));
unitConverter.SetConversionFunction<HowMuch>(HowMuchUnit.Tons, HowMuchUnit.Lots, x => new HowMuch(x.Value * 10, HowMuchUnit.Lots));
unitConverter.SetConversionFunction<HowMuch>(HowMuchUnit.Tons, HowMuchUnit.Some, x => new HowMuch(x.Value * 20, HowMuchUnit.Some));

var from = new HowMuch(10, HowMuchUnit.Tons);
IQuantity Convert(HowMuchUnit toUnit) => unitConverter.GetConversionFunction<HowMuch>(from.Unit, toUnit)(from);

Console.WriteLine($"Convert 10 tons to:");
Console.WriteLine(Convert(HowMuchUnit.Some)); // 200 sm
Console.WriteLine(Convert(HowMuchUnit.Lots)); // 100 lts
Console.WriteLine(Convert(HowMuchUnit.Tons)); // 10 tns
Run Code Online (Sandbox Code Playgroud)

Sample quantity

public enum HowMuchUnit
{
    Some,
    Lots,
    Tons
}

public struct HowMuch : IQuantity
{
    public HowMuch(double value, HowMuchUnit unit)
    {
        Unit = unit;
        Value = value;
    }

    Enum IQuantity.Unit => Unit;
    public HowMuchUnit Unit { get; }

    public double Value { get; }

    #region IQuantity

    private static readonly HowMuch Zero = new HowMuch(0, HowMuchUnit.Some);

    public QuantityType Type => QuantityType.Undefined;
    public BaseDimensions Dimensions => BaseDimensions.Dimensionless;

    public QuantityInfo QuantityInfo => new QuantityInfo(Type,
        new UnitInfo[]
        {
                new UnitInfo<HowMuchUnit>(HowMuchUnit.Some, BaseUnits.Undefined),
                new UnitInfo<HowMuchUnit>(HowMuchUnit.Lots, BaseUnits.Undefined),
                new UnitInfo<HowMuchUnit>(HowMuchUnit.Tons, BaseUnits.Undefined),
        },
        HowMuchUnit.Some,
        Zero,
        BaseDimensions.Dimensionless);

    public double As(Enum unit) => Convert.ToDouble(unit);

    public double As(UnitSystem unitSystem) => throw new NotImplementedException();

    public IQuantity ToUnit(Enum unit)
    {
        if (unit is HowMuchUnit howMuchUnit) return new HowMuch(As(unit), howMuchUnit);
        throw new ArgumentException("Must be of type HowMuchUnit.", nameof(unit));
    }

    public IQuantity ToUnit(UnitSystem unitSystem) => throw new NotImplementedException();

    public override string ToString() => $"{Value} {UnitAbbreviationsCache.Default.GetDefaultAbbreviation(Unit)}";
    public string ToString(string format, IFormatProvider formatProvider) => $"HowMuch ({format}, {formatProvider})";
    public string ToString(IFormatProvider provider) => $"HowMuch ({provider})";
    public string ToString(IFormatProvider provider, int significantDigitsAfterRadix) => $"HowMuch ({provider}, {significantDigitsAfterRadix})";
    public string ToString(IFormatProvider provider, string format, params object[] args) => $"HowMuch ({provider}, {string.Join(", ", args)})";

    #endregion
}
Run Code Online (Sandbox Code Playgroud)