如何在 C# 中直接键入强制转换装箱结构?

Mar*_*ark 4 c# struct implicit-conversion

我有一个结构体的命名空间,它代表各种测量单位(米、英尺、英寸等)...总共 12 个,由 T4 模板生成:)。

每个结构体都带有隐式转换运算符以支持将值转换为任何其他测量值类型,因此以下语法是合法的:

var oneThousandMeters = new Meters(1000);    
Kilometers aKilo = oneThousandMeters ;     // implicit cast OK. Value = 1 Km
Run Code Online (Sandbox Code Playgroud)

为了增加乐趣,有一个名为Distance 的包罗万象的类,它可以保存任何测量单位,并且还可以隐式地与测量值进行转换...

var magnum = new Distance(12, DistanceUnits.Inches); 
Feet wifesDelight = magnum;               // implicit cast OK. Value = 1 foot.
Run Code Online (Sandbox Code Playgroud)

遵循 .NET 框架标准,所有字符串格式化和解析均由外部 FormatProvider 处理,该 FormatProvider 实现 ICustomFormatter。遗憾的是,这意味着该值在传递给 Format 方法时会被装箱,并且 format 方法需要针对每个已知的测量类型测试该对象,然后才能对其进行操作。在内部,Format 方法只是将测量值转换为距离值,所以问题来了......

问题:

public string Format(string format, object arg, IFormatProvider formatProvider)
{
    Distance distance;           

    // The following line is desired, but fails if arg != typeof(Distance)   
    distance = (Distance)arg;    

    // But the following tedious code works:
    if(arg is Distance)
       distance = (Distance)arg;
    else if(arg is Meters)
       distance = (Distance)(Meters)arg;     // OK. compile uses implicit cast. 
    else if(arg is Feet)
       distance = (Distance)(Feet)arg;       // OK. compile uses implicit cast. 
    else if(arg is Inches)
       distance = (Distance)(Inches)arg;     // OK. compile uses implicit cast. 
    else
        ... // tear you hair out for all 12 measurement types
}
Run Code Online (Sandbox Code Playgroud)

有没有解决方案,或者这只是值类型无法解决的缺点之一?

PS:我已经检查过这篇文章,虽然问题相似,但这不是我要找的。

Jon*_*eet 5

嗯,这是将拆箱转换与用户定义转换分开的问题。您希望两者都发生 - 并且您必须指定要拆箱的类型,并让编译器知道您何时需要用户定义的转换。除非您使用动态类型,否则必须在编译时选择用户定义的转换,因此编译器需要知道它尝试从哪种类型进行转换。

一种选择是拥有一个所有结构都实现的IDistance 接口。然后你就可以使用:

IDistance distanceArg = arg as IDistance;
if (distanceArg != null)
{
    Distance distance = distanceArg.ToDistance();
}
Run Code Online (Sandbox Code Playgroud)

由于您已经有了一个装箱值,因此使用接口不会导致额外的装箱或类似的情况。每个ToDistance实现可能只使用隐式转换:

public Distance ToDistance()
{
    return this;
}
Run Code Online (Sandbox Code Playgroud)

...或者您可以使用转换ToDistance